基本原理:
1.可變長度編碼 & 跳過可選字段
2.作用在網(wǎng)絡傳輸過程
一涎显、存儲方式
TAG? [LENGTH]? VALUE
TAG:? filedId(前五位bit)+ WIRE_TYPE(低三位bit)? ? 1 byte?
LENGTH: WIRE_TYPE = 2 時 存在? ? ? 1byte
VALUE:WIRE_TYPE = varint 時 采用小端存儲模式,其他正常讀取?
二悼尾、WIRE_TYPE
0: varint變長編碼,主要就是依靠這個來減小存儲體積
1:定長 8byte
2: 指定長度
3隘庄、4 :已廢棄
5:定長 4 byte
三曹铃、Varint 原理
int32 類型的數(shù)字,一般需要 4 個 byte 來表示总放。但是采用 Varint,對于很小的 int32 類型的數(shù)字好爬,則可以用 1 個 byte 來表示局雄。
采用 Varint 表示法,大的數(shù)字則需要 5 個 byte 來表示存炮。從統(tǒng)計的角度來說炬搭,一般不會所有的消息中的數(shù)字都是大數(shù),因此大多數(shù)情況下穆桂,采用 Varint 后宫盔,可以用更少的字節(jié)數(shù)來表示數(shù)字信息
小端存儲模式
示例1:
對于數(shù)字1 對應的二進制是 :00000000 00000000 00000000 00000001
PB 只用一個字節(jié)就可以存儲該值:即 0 00000001
第一位0 表示該字節(jié)就是結束字節(jié),后七位 0000001 即表示十進制的數(shù)字 1
示例2:
對于數(shù)字 500享完,對應的二進制:00000000 00000000 00000001 11110100
? ? ? ? 從最低位開始 七位分割 即:1110100 0000011
? ? ? ? PB編碼用兩個字節(jié)表示 :1 1110100 0 0000011
? ? ? ? 解碼:高位是 1 表示 還要讀后面一個字節(jié)
? ? ? ? 去掉最高位:1110100 0000011
? ? ? ? 由于是小端模式:組合后是 00000111110100 十進制即是500
三飘言、zigTag 編碼(解決負數(shù)占用多字節(jié)問題)
原碼:最高位為符號位,剩余位表示絕對值驼侠;
反碼:除符號位外姿鸿,對原碼剩余位依次取反;
補碼:對于正數(shù)倒源,補碼為其自身苛预;對于負數(shù),除符號位外對原碼剩余位依次取反然后+1
原碼缺陷:
1笋熬、 0 有兩種表現(xiàn)形式 :00000000 和 10000000
2热某、計算錯誤:1 + (-1) = 00000001 + 10000001 = 10000010 = -2
補碼解決的問題:1+(-1) = 00000001+ 11111111 = 00000000 = 0
zizag會對負數(shù)進行一輪哈希映射,拿到hash值后胳螟,編碼策略:直接去掉hash值的前導0之后的byte作為壓縮編碼
四昔馋、一些示例
示例1:
message Test1 {
? ? optional int32 a = 1; //表明是 fildId 是 1
}
創(chuàng)建 Test1消息并把a設置為150
編碼后:08 96 01
編碼后對應二進制:00001000 10010110 00000001
解碼:
(1)000001000 后三位:000 表示W(wǎng)IRE_TYPE = 0,即 Varint;00001 = 1 表示對應第一個 fieldId;
(2)10010110 00000001:
10010110 最高位 1 表示還需要讀取下一個字節(jié),剩余 0010110糖耸;
00000001 最高位表示無需讀下一個字節(jié)秘遏,剩余 0000001;
按照小端模式進行拼接:00000010010110 轉化為10進制 即 150
示例2:嵌套消息(嵌套的消息會作為WIRE_TYPE = 2 來對待)
Message Test2{
? ? ? ? optional Test1 c = 3;
}
如示例1 給Test1 a 賦值 150
則得到的編碼:1a 03 08 96 01
1a 對應 2進制:00011010 后三位表示 有線類型 2嘉竟,前五位表示 3 對應的 是fieldId
03 表示長度:及3個字節(jié)的長度
08 96 01 :見示例一分析過程