2011-08-24 3 views
18

BinaryFormatter과 Protobuf-net 시리얼 라이저 사이의 약간의 비교를하고 있었는데 나는 내가 found인데 상당히 기뻤지 만, Protobuf-net은 객체를 내가 사용한다면 얻을 수있는 것보다 작은 바이트 배열로 직렬화 할 수 있었다. 모든 속성의 값을 메타 데이터없이 바이트 배열에 썼습니다. 그래서 Protobuf-NET은 기본적으로 약간의 압축을 제공합니까, Protobuf-net에는 직렬화를위한 빌드 인 압축 기능이 있습니까?

난 당신이 trueAsReference를 설정하면 Protobuf-NET 지원 문자열 인턴 알지만,이 경우에 것을 안할거야?

var simpleObject = new SimpleObject 
         { 
          Id = 10, 
          Name = "Yan", 
          Address = "Planet Earth", 
          Scores = Enumerable.Range(1, 10).ToList() 
         }; 

using (var memStream = new MemoryStream()) 
{ 
    var binaryWriter = new BinaryWriter(memStream); 
    // 4 bytes for int 
    binaryWriter.Write(simpleObject.Id);  
    // 3 bytes + 1 more for string termination 
    binaryWriter.Write(simpleObject.Name);  
    // 12 bytes + 1 more for string termination 
    binaryWriter.Write(simpleObject.Address); 
    // 40 bytes for 10 ints 
    simpleObject.Scores.ForEach(binaryWriter.Write); 

    // 61 bytes, which is what I expect 
    Console.WriteLine("BinaryWriter wrote [{0}] bytes", 
     memStream.ToArray().Count()); 
} 

using (var memStream = new MemoryStream()) 
{ 
    ProtoBuf.Serializer.Serialize(memStream, simpleObject); 

    // 41 bytes! 
    Console.WriteLine("Protobuf serialize wrote [{0}] bytes", 
     memStream.ToArray().Count()); 
} 

편집 : 여기

당신이 직접보고하기 위해 실행할 수있는 몇 가지 코드의 추가하려면 SimpleObject 클래스는 다음과 같습니다 없다 깜빡 :

[Serializable] 
[DataContract] 
public class SimpleObject 
{ 
    [DataMember(Order = 1)] 
    public int Id { get; set; } 

    [DataMember(Order = 2)] 
    public string Name { get; set; } 

    [DataMember(Order = 3)] 
    public string Address { get; set; } 

    [DataMember(Order = 4)] 
    public List<int> Scores { get; set; } 
} 

답변

26

없음은하지 않습니다; protobuf 스펙에 지정된 "압축"이 없습니다. 그러나 (기본값으로) "varint encoding"을 사용합니다. 정수 값은 가변 길이 인코딩으로 작은 값은 공간을 덜 사용합니다. 그래서 0-127은 헤더에 1 바이트를 더한 값을 취합니다. varint 그 자체가은 음수에 대해 꽤 어지럽게 쓰이기 때문에 작은 크기 인 숫자를 작게 (기본적으로 양수와 음수 쌍을 인터리빙) 허용하는 "지그재그"인코딩도 지원됩니다.

사실, Scores에 대한 귀하의 경우 당신은 또한 [ProtoMember(4, IsPacked = true)] 또는 V2의 TypeModel를 통해 상당 (V2 어느 접근 방식을 지원합니다) 중 하나가 필요합니다 "포장"인코딩을 봐야한다. 이렇게하면 단일 헤더를 작성하고 길이가 인 을 작성하여 값 당 헤더의 오버 헤드를 피할 수 있습니다. "Packed"는 varint/zigzag와 함께 사용할 수 있습니다. 을 알고있는 값이 크고 예측할 수없는 시나리오에 대해서는 고정 길이 인코딩이 있습니다.

참고 : 데이터에 많은 텍스트가있는 경우 gzip 또는 수분을 통해 추가로 실행할 수도 있습니다. 이 아니면 gzip과 deflate가 더 커질 수 있습니다.

와이어 형식 개요 is here; 이해하기가 까다로울 수는 없으며 최선의 최적화 방법을 계획하는 데 도움이 될 수 있습니다.

+0

감사합니다. 이제는 모두 의미가 있습니다! – theburningmonk

+0

protobuf가 128 값에 대해서만 1 바이트를 만드는 이유는 무엇입니까? 8 비트로 256 개의 서로 다른 값을 쓸 수 있습니다. – tobi

+6

@tobi 필드 번호에 대해 "varint"인코딩을 사용합니다. 이는 7 비트 페이로드를 의미하고 1 비트는 "읽을 다른 바이트가 있습니다"라는 의미입니다. MSB가 0이 될 때까지 계속 읽습니다. –

관련 문제