2011-03-06 53 views
3

我有一個協議緩衝設置是這樣的:協議緩衝區數組中的字節浪費?

[ProtoContract] 
Foo 
{ 
    [ProtoMember(1)] 
    Bar[] Bars; 
} 

單杆被編碼爲67字節協議緩衝器。這聽起來很正確,因爲我知道Bar幾乎只是一個64字節的數組,然後長度前綴有3個字節開銷。

但是,當我用20條數組編碼一個Foo時,它需要1362個字節。 20 * 67是1340,所以只有22個字節的開銷用於編碼數組!

爲什麼這佔用了太多空間?我能做些什麼來減少它嗎?

+1

和Foo本身是免費的嗎?它應該佔用一些空間嗎? – user492238 2011-03-06 17:07:56

+0

它應該佔用一些空間,但22個字節是一個很大的空間! – Martin 2011-03-06 17:16:30

+2

在1340之上的22個字節不是'那麼多',當然不是用於序列化。繼續你的生活吧。 – 2011-03-06 18:32:34

回答

5

這個開銷是很簡單,它需要知道其中每個20個對象的開始和結束的信息。在不破壞格式的情況下,我可以做任何不同的事情(即做與規範相反的事情)。

如果你真的想血淋淋的細節:

數組或列表(如果我們排除「包裝」,它在這裏不適用),只需子消息的重複塊。有兩種佈局可用於子消息;字符串和組。用字符串,佈局:

[header][length][data] 

其中header是(在這種情況下與場1十六進制08)的導線型和場數的varint編碼醪,length是varint編碼大小data,數據是子對象本身。對於小對象(data小於128字節),這通常意味着每個對象有2個字節的開銷,具體取決於:字段號(15以上的字段佔用更多空間),以及b:數據的大小。

隨着一組,佈局:

[header][data][footer] 

其中header是線型和場數(在這種情況下,與場1十六進制0B)的varint編碼醪,data是子對象,並且footer是另一個varint mash,用於指示對象的結尾(在此例中爲字段1的十六進制0C)。

團體普遍不太受歡迎,但他們的優勢是他們不會招致任何開銷,因爲data的規模增長。對於小的字段號(小於16),開銷是每個對象2字節。當然,你需要支付大型現場數字的兩倍。

+0

謝謝馬克,我懷疑這可能是我遇到的協議中的一個惡毒案件。 – Martin 2011-03-07 01:40:33

2

默認情況下,數組實際上並不是作爲數組傳遞的,而是作爲重複的成員傳遞的,這些成員的開銷略高一些。

所以我想你實際上有1字節的開銷每個重複的數組元素,加上2額外的字節開銷頂部。

您可以通過使用「packed」數組來減少開銷。 protobuf網支持這樣的:http://code.google.com/p/protobuf-net/

爲二進制格式的文檔是在這裏:http://code.google.com/apis/protocolbuffers/docs/encoding.html

+0

奇數,在數組上使用打包會觸發一個異常「打包緩衝區不支持wire-type:String」。這很奇怪,因爲酒吧不是一個字符串! – Martin 2011-03-06 18:01:39

+1

@馬丁 - 就protobuf規範而言:是的。這只是特定佈局的名稱 - 它不代表* text *字符串。對象有兩種可能的格式;字符串和組。 Packed確實可以消除頭文件的開銷,但只適用於非常基本的類型,例如整數和浮點數;不是對象。 – 2011-03-06 22:57:59