IT TIP

직렬화 대 Google 프로토콜 버퍼 향상?

itqueen 2020. 11. 19. 22:43
반응형

직렬화 대 Google 프로토콜 버퍼 향상?


이 라이브러리에 대한 경험이있는 사람이 선호하는 라이브러리에 대한 의견이 있습니까? 성능상의 차이나 사용상의 어려움이 있었습니까?


나는 두 시스템을 약간 가지고 놀았고, 심각하지 않고, 단순한 해커 쉬 한 것들만 가지고 놀았지만, 라이브러리를 사용하는 방법에는 실제 차이가 있다고 느꼈습니다.

boost :: serialization을 사용하면 먼저 자신의 구조체 / 클래스를 작성한 다음 보관 메서드를 추가하지만 여전히 데이터 멤버로 사용할 수있는 매우 "슬림 한"클래스가 남아 있습니다.

프로토콜 버퍼를 사용하면 단순한 구조에서도 생성되는 코드의 양이 상당히 많으며 생성되는 구조와 코드는 작동을 위해 더 의미가 있으며 프로토콜 버퍼의 기능을 사용하여 자체 내부 구조와 데이터를 전송합니다. .


나는 오랫동안 Boost Serialization을 사용해 왔고 프로토콜 버퍼를 파헤 쳤으며 정확히 동일한 목적을 가지고 있지 않다고 생각합니다. BS (그것이 오는 것을 보지 못함)는 C ++ 객체를 스트림에 저장하는 반면 PB는 당신이 읽고받는 교환 형식입니다.

PB의 데이터 모델은 훨씬 간단합니다. 모든 종류의 int와 float, 문자열, 배열, 기본 구조를 얻습니다. BS를 사용하면 모든 개체를 한 번에 직접 저장할 수 있습니다.

즉, BS를 사용하면 와이어에서 더 많은 데이터를 얻을 수 있지만 모든 개체 구조를 다시 빌드 할 필요는 없지만 프로토콜 버퍼는 더 작지만 아카이브를 읽은 후에 수행해야 할 작업이 더 많습니다. 이름에서 알 수 있듯이 하나는 프로토콜 (언어에 구애받지 않고 공간 효율적인 데이터 전달)을위한 것이고 다른 하나는 직렬화 (두뇌없는 객체 저장)를위한 것입니다.

그렇다면 더 중요한 것은 속도 / 공간 효율성 또는 깨끗한 코드입니까?


내가 믹스에 추가 할 boost.serialization에 대한 몇 가지 추가 문제가 있습니다. 주의 사항 : 문서를 훑어 보는 것 이상의 프로토콜 버퍼에 대한 직접적인 경험이 없습니다.

boost 및 boost.serialization이 그 기능에 뛰어나다 고 생각하지만 함께 제공되는 기본 아카이브 형식이 유선 형식에 적합하지 않다는 결론에 도달했습니다.

클래스의 버전 (다른 답변에서 언급했듯이 boost.serialization에는 데이터 버전 관리에 대한 일부 지원이 있음)과 서로 다른 버전의 직렬화 라이브러리 간의 호환성 을 구분하는 것이 중요합니다 .

최신 버전의 boost.serialization 은 이전 버전이 역 직렬화 할 수있는 아카이브를 생성하지 않을 수 있습니다 . (반대는 사실이 아닙니다. 최신 버전은 항상 이전 버전에서 만든 아카이브를 역 직렬화하기위한 것입니다.) 이로 인해 다음과 같은 문제가 발생했습니다.

  • 우리의 클라이언트와 서버 소프트웨어는 모두 다른 사람이 사용하는 직렬화 된 객체를 생성하므로 클라이언트와 서버를 잠금 단계에서 업그레이드하는 경우에만 새로운 boost.serialization으로 이동할 수 있습니다. (이는 클라이언트를 완전히 제어 할 수없는 환경에서는 상당히 어려운 일입니다.)
  • Boost는 공유 부분이있는 하나의 큰 라이브러리로 번들로 제공되며 직렬화 코드와 boost 라이브러리의 다른 부분 (예 : shared_ptr)이 모두 같은 파일에서 사용 중일 수 있습니다. 부스트의 어떤 부분도 업그레이드 할 수 없기 때문에 업그레이드 할 수 없습니다. t 업그레이드 boost.serialization. 여러 버전의 부스트를 단일 실행 파일에 연결하는 것이 가능 / 안전 / 정상인지 또는 이전 버전의 부스트에 유지해야하는 비트를 별도의 비트로 리팩토링 할 예산 / 에너지가 있는지 확실하지 않습니다. 실행 파일 (이 경우에는 DLL).
  • 우리가 갇힌 이전 버전의 부스트는 우리가 사용하는 최신 버전의 컴파일러를 지원하지 않으므로 우리는 이전 버전의 컴파일러에도 갇혀 있습니다.

Google은 실제로 프로토콜 버퍼 와이어 형식을 게시하는 것으로 보이며 Wikipedia는이를 순방향 호환, 역방향 호환 이라고 설명합니다 (비록 Wikipedia는 프로토콜 버퍼 라이브러리 버전 관리가 아닌 데이터 버전 관리를 참조한다고 생각하지만). 이들 중 어느 것도 순방향 호환성을 보장하지는 않지만 나에게는 더 강력한 표시처럼 보입니다.

요약하면 클라이언트 및 서버를 잠금 단계에서 업그레이드 할 수없는 경우 프로토콜 버퍼와 같은 잘 알려진 게시 된 유선 형식을 선호합니다 .

각주 : 관련 답변위한 뻔뻔한 플러그 .


직렬화 향상

  • 스트림에 데이터를 쓰기위한 라이브러리입니다.
  • 데이터를 압축하지 않습니다.
  • 자동으로 데이터 버전 관리를 지원하지 않습니다.
  • STL 컨테이너를 지원합니다.
  • 기록 된 데이터의 속성은 선택한 스트림 (예 : 엔디안, 압축)에 따라 다릅니다.

프로토콜 버퍼

  • 인터페이스 설명에서 코드를 생성합니다 (기본적으로 C ++, Python 및 Java 지원. 타사에서 C, C # 및 기타 지원).
  • 선택적으로 데이터를 압축합니다.
  • 데이터 버전 관리를 자동으로 처리합니다.
  • 플랫폼 간 엔디안 스와핑을 처리합니다.
  • STL 컨테이너를 지원하지 않습니다.

Boost 직렬화는 객체를 직렬화 된 데이터 스트림으로 변환하기위한 라이브러리입니다. 프로토콜 버퍼는 동일한 작업을 수행하지만 다른 작업 (예 : 버전 관리 및 엔디안 스와핑)도 수행합니다. 부스트 직렬화는 "작은 간단한 작업"에 대해 더 간단합니다. 프로토콜 버퍼는 아마도 "더 큰 인프라"에 더 좋습니다.

수정 : 24-11-10 : BS 버전 관리에 "자동으로"추가되었습니다.


부스트 직렬화에 대한 경험이 없지만 프로토콜 버퍼를 사용했습니다. 저는 프로토콜 버퍼를 많이 좋아합니다. 다음을 명심하십시오 ( 부스트에 대한 지식 없이이 말을합니다 ).

  • 내가하지 않도록 프로토콜 버퍼는 매우 효율적 상상 그 심각한 문제 대 부스트되고.
  • 프로토콜 버퍼는 다른 언어 (Python 및 Java 등)에서 작동하는 중간 표현을 제공합니다. C ++ 만 사용하고 있다는 것을 알고 있다면 부스트가 더 좋을 수도 있지만 다른 언어를 사용하는 옵션이 좋습니다.
  • 프로토콜 버퍼는 데이터 컨테이너와 비슷합니다. 상속과 같은 객체 지향 특성이 없습니다. 직렬화하려는 구조에 대해 생각하십시오.
  • "선택적"필드를 추가 할 수 있으므로 프로토콜 버퍼는 유연합니다. 이것은 기본적으로 호환성을 깨지 않고 프로토콜 버퍼의 구조를 변경할 수 있음을 의미합니다.

도움이 되었기를 바랍니다.


boost.serialization은 C ++ 컴파일러 만 필요하며 다음과 같은 구문 설탕을 제공합니다.

serialize_obj >> archive;
// ...
unserialize_obj << archive;

저장 및로드를 위해. C ++ 만 사용하는 언어라면 boost.serialization에 심각한 기회를 주어야합니다.

Google 프로토콜 버퍼를 빠르게 살펴 보았습니다. 내가 본 것에서 나는 그것이 boost.serialization과 직접 비교할 수 없다고 말할 것입니다. .proto 파일 용 컴파일러를 도구 체인에 추가하고 .proto 파일 자체를 유지해야합니다. API는 boost.serialization처럼 C ++에 통합되지 않습니다.

boost.serialization은 C ++ 객체를 직렬화하기 위해 설계된 작업을 매우 잘 수행합니다. :) OTOH Google 프로토콜 버퍼와 같은 쿼리 API는 더 많은 유연성을 제공합니다.

지금까지 boost.serialization 만 사용했기 때문에 성능 비교에 대해서는 언급 할 수 없습니다.


Boost Serialization에 대한 위의 수정 ( 그 대답이라고 추측 ) :

지원 데이터 버전 관리를 허용 합니다.

압축이 필요한 경우 압축 된 스트림을 사용하십시오.

인코딩은 텍스트, 바이너리 또는 XML 일 수 있으므로 플랫폼 간의 엔디안 스와핑을 처리 할 수 ​​있습니다.


부스트 라이브러리를 사용하여 구현 한 적은 없지만 Google protobuff가 좀 더 신중하고 코드가 훨씬 깨끗하고 읽기 쉽습니다. 사용하려는 다양한 언어를 살펴보고 코드와 문서를 읽고 마음을 정하는 것이 좋습니다.

protobufs에서 내가 가진 한 가지 어려움은 생성 된 코드에서 매우 일반적으로 사용되는 함수 인 GetMessage ()라는 이름을지었습니다. 물론 Win32 GetMessage 매크로와 충돌합니다.

나는 여전히 protobufs를 적극 권장합니다. 매우 유용합니다.


엔지니어링 분야의 거의 모든 것과 마찬가지로 제 대답은 ... "상황에 따라 다릅니다."

둘 다 잘 테스트되고 검증 된 기술입니다. 둘 다 데이터를 가져 와서 다른 곳으로 보내기에 친숙한 것으로 바꿉니다. 둘 다 충분히 빠를 수 있으며 여기 또는 저기에서 바이트를 실제로 계산하는 경우 둘 중 하나에 만족하지 않을 것입니다 (두 생성 된 패킷 모두 XML 또는 JSON의 작은 부분이 될 것입니다).

저에게는 실제로 워크 플로와 다른 쪽 끝에 C ++ 이외의 것이 필요한지 여부에 달려 있습니다.

메시지 내용을 먼저 파악하고 처음부터 시스템을 구축하려면 프로토콜 버퍼를 사용하십시오. 추상적 인 방식으로 메시지를 생각한 다음 원하는 언어로 코드를 자동 생성 할 수 있습니다 (제 3 자 플러그인은 거의 모든 것에 사용할 수 있습니다). 또한 Protocol Buffers를 사용하면 협업이 단순화됩니다. .proto 파일을 보내면 다른 팀이 어떤 데이터가 전송되는지 분명하게 알 수 있습니다. 나는 또한 그들에게 아무것도 부과하지 않습니다. 그들이 Java를 사용하고 싶다면 계속하십시오!

이미 C ++로 클래스를 구축했고 (이는 더 자주 발생했습니다) 지금 그 데이터를 유선으로 보내고 싶다면 Boost Serialization은 분명히 의미가 있습니다 (특히 다른 곳에 이미 Boost 종속성이있는 경우) ).


나는 이것이 이제 오래된 질문이라는 것을 알고 있지만 2 펜스를 던질 것이라고 생각했습니다!

부스트를 사용하면 클래스에서 데이터 유효성 검사를 작성할 수 있습니다. 이것은 데이터 정의와 유효성 검사가 모두 한곳에 있기 때문에 좋습니다.

GPB로 할 수있는 최선의 방법은 .proto 파일에 주석을 달고 그것을 사용하는 사람이 그것을 읽고,주의를 기울이고, 유효성 검사를 스스로 구현하기를 바라는 모든 희망에 반대하는 것입니다.

말할 필요도없이 네트워크 스트림의 다른 쪽 끝에있는 다른 사람에게 자신과 같은 힘으로이를 수행하는 경우 이것은 가능성이 낮고 신뢰할 수 없습니다. 또한 유효성에 대한 제약이 변경되면 여러 코드 변경을 계획, 조정 및 수행해야합니다.

따라서 저는 GPB가 모든 팀원들과 정기적으로 만나 대화 할 기회가 거의없는 개발에는 부적절하다고 생각합니다.

== 편집하다 ==

제가 의미하는 것은 다음과 같습니다.

message Foo
{
    int32 bearing = 1;
}

이제 유효한 범위가 무엇인지 누가 말 bearing할까요? 우리는 가질 수 있습니다

message Foo
{
    int32 bearing = 1;  // Valid between 0 and 359
}

그러나 그것은 다른 누군가가 이것을 읽고 코드를 작성하는 것에 달려 있습니다. 예를 들어 편집하면 제약 조건이 다음과 같습니다.

message Foo
{
    int32 bearing = 1;  // Valid between -180 and +180
}

이 .proto를 사용하여 코드를 업데이트 한 모든 사람에게 전적으로 의존합니다. 이는 신뢰할 수없고 비용이 많이 듭니다.

적어도 Boost 직렬화를 사용하면 단일 C ++ 클래스를 배포하고 데이터 유효성 검사가 바로 내장 될 수 있습니다. 이러한 제약 조건이 변경되면 다른 사람이 동일한 버전의 소스 코드를 사용하고 있는지 확인하는 것 외에 다른 작업을 수행 할 필요가 없습니다.

대안

There is an alternative: ASN.1. This is ancient, but has some really, really, handy things:

Foo ::= SEQUENCE
{
   bearing INTEGER (0..359)
}

Note the constraint. So whenever anyone consumes this .asn file, generates code, they end up with code that will automatically check that bearing is somewhere between 0 and 359. If you update the .asn file,

Foo ::= SEQUENCE
{
   bearing INTEGER (-180..180)
}

all they need to do is recompile. No other code changes are required.

You can also do:

bearingMin INTEGER ::= 0
bearingMax INTEGER ::= 360

Foo ::= SEQUENCE
{
   bearing INTEGER (bearingMin..<bearingMax)
}

Note the <. And also in most tools the bearingMin and bearingMax can appear as constants in the generated code. That's extremely useful.

Constraints can be quite elaborate:

Garr ::= INTEGER (0..10 | 25..32)

Look at Chapter 13 in this PDF; it's amazing what you can do;

Arrays can be constrained too:

Bar ::= SEQUENCE (SIZE(1..5)) OF Foo
Sna ::= SEQUENCE (SIZE(5)) OF Foo
Fee ::= SEQUENCE 
{
    boo SEQUENCE (SIZE(1..<6)) OF INTEGER (-180<..<180)
}

ASN.1 is old fashioned, but still actively developed, widely used (your mobile phone uses it a lot), and far more flexible than most other serialisation technologies. About the only deficiency that I can see is that there is no decent code generator for Python. If you're using C/C++, C#, Java, ADA then you are well served by a mixture of free (C/C++, ADA) and commercial (C/C++, C#, JAVA) tools.

I especially like the wide choice of binary and text based wireformats. This makes it extremely convenient in some projects. The wireformat list currently includes:

  • BER (binary)
  • PER (binary, aligned and unaligned. This is ultra bit efficient. For example, and INTEGER constrained between 0 and 15 will take up only 4 bits on the wire)
  • OER
  • DER (another binary)
  • XML (also XER)
  • JSON (brand new, tool support is still developing)

plus others.

Note the last two? Yes, you can define data structures in ASN.1, generate code, and emit / consume messages in XML and JSON. Not bad for a technology that started off back in the 1980s.

Versioning is done differently to GPB. You can allow for extensions:

Foo ::= SEQUENCE
{
   bearing INTEGER (-180..180),
   ...
}

This means that at a later date I can add to Foo, and older systems that have this version can still work (but can only access the bearing field).

I rate ASN.1 very highly. It can be a pain to deal with (tools might cost money, the generated code isn't necessarily beautiful, etc). But the constraints are a truly fantastic feature that has saved me a whole ton of heart ache time and time again. Makes developers whinge a lot when the encoders / decoders report that they've generated duff data.

Other links:

Observations

To share data:

  • Code first approaches (e.g. Boost serialisation) restrict you to the original language (e.g. C++), or force you to do a lot of extra work in another language
  • Schema first is better, but
    • A lot of these leave big gaps in the sharing contract (i.e. no constraints). GPB is annoying in this regard, because it is otherwise very good.
    • Some have constraints (e.g. XSD, JSON), but suffer patchy tool support.
    • For example, Microsoft's xsd.exe actively ignores constraints in xsd files (MS's excuse is truly feeble). XSD is good (from the constraints point of view), but if you cannot trust the other guy to use a good XSD tool that enforces them for him/her then the worth of XSD is diminished
    • JSON validators are ok, but they do nothing to help you form the JSON in the first place, and aren't automatically called. There's no guarantee that someone sending you JSON message have run it through a validator. You have to remember to validate it yourself.
    • ASN.1 tools all seem to implement the constraints checking.

So for me, ASN.1 does it. It's the one that is least likely to result in someone else making a mistake, because it's the one with the right features and where the tools all seemingly endeavour to fully implement those features, and it is language neutral enough for most purposes.

To be honest, if GPB added a constraints mechanism that'd be the winner. XSD is close but the tools are almost universally rubbish. If there were decent code generators of other languages, JSON schema would be pretty good.

If GPB had constraints added (note: this would not change any of the wire formats), that'd be the one I'd recommend to everyone for almost every purpose. Though ASN.1's uPER is very useful for radio links.


You can use boost serialization in tight conjunction with your "real" domain objects, and serialize the complete object hierarchy (inheritance). Protobuf does not support inheritance, so you will have to use aggregation. People argue that Protobuf should be used for DTOs (data transfer objects), and not for core domain objects themselves. I have used both boost::serialization and protobuf. The Performance of boost::serialization should be taken into account, cereal might be an alternative.

참고URL : https://stackoverflow.com/questions/1061169/boost-serialization-vs-google-protocol-buffers

반응형