2011-08-24 21 views
18

Tôi đã làm một số so sánh giữa BinaryFormatter và Protobuf-net serializer và khá hài lòng với những gì tôi found, nhưng điều lạ là Protobuf-net quản lý để sắp xếp các đối tượng vào một mảng byte nhỏ hơn những gì tôi sẽ nhận được nếu tôi chỉ đã viết giá trị của mỗi thuộc tính vào một mảng các byte mà không có bất kỳ siêu dữ liệu nào.Protobuf-net có tích hợp nén để tuần tự hóa không?

Tôi biết Protobuf-net hỗ trợ chuỗi thực tập nếu bạn đặt AsReference thành true, nhưng tôi không làm điều đó trong trường hợp này, do đó Protobuf-net cung cấp một số nén theo mặc định?

Dưới đây là một số mã, bạn có thể chạy để xem cho chính mình:

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()); 
} 

EDIT: Quên để thêm, lớp SimpleObject trông như thế này:

[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; } 
} 

Trả lời

26

Không nó không; không có "nén" như được chỉ định trong thông số protobuf; tuy nhiên, nó (theo mặc định) sử dụng "mã hóa varint" - một bảng mã có độ dài biến đổi cho dữ liệu số nguyên có nghĩa là các giá trị nhỏ sử dụng ít không gian hơn; vì vậy 0-127 mất 1 byte cộng với tiêu đề. Lưu ý rằng số của chính nó là khá lố bịch đối với số âm, vì vậy mã hóa "ngoằn ngoèo" cũng được hỗ trợ cho phép số nhỏ độ lớn nhỏ (về cơ bản, xen kẽ các cặp âm và dương).

Thực tế, trong trường hợp của bạn là Scores, bạn cũng nên xem mã hóa "đóng gói", yêu cầu [ProtoMember(4, IsPacked = true)] hoặc tương đương qua TypeModel trong v2 (v2 hỗ trợ phương pháp tiếp cận). Điều này tránh được phí trên đầu trang cho mỗi giá trị, bằng cách viết một tiêu đề và kết hợp với chiều dài. "Đóng gói" có thể được sử dụng với varint/zigzag. Ngoài ra còn có các mã hóa có độ dài cố định cho các trường hợp mà bạn biết các giá trị có khả năng lớn và không thể đoán trước.

Cũng lưu ý: nhưng nếu dữ liệu của bạn có nhiều văn bản, bạn có thể hưởng lợi từ việc chạy bổ sung thông qua gzip hoặc giảm tốc; nếu nó không, thì cả gzip và giảm phát có thể khiến nó trở nên lớn hơn.

Tổng quan về định dạng dây is here; nó không phải là rất khó hiểu, và có thể giúp bạn có kế hoạch làm thế nào tốt nhất để tiếp tục tối ưu hóa.

+0

cảm ơn, tất cả đều có ý nghĩa ngay bây giờ! – theburningmonk

+0

Tại sao protobuf chỉ tạo 1 byte cho 128 giá trị? 8 bit cho phép viết 256 giá trị khác nhau. – tobi

+6

@tobi nó sử dụng mã hóa "varint" cho số trường - nghĩa là tải trọng 7 bit và 1 bit "có một byte khác để đọc". Bạn tiếp tục đọc cho đến khi MSB bằng không. –