MessagePack 新型序列化反序列化方案
進入在學習redis的時候,在文中看到了關於MessagePack的簡介,發現非常有意思,於是就花了點時間大致了解了下。
MessagePack介紹:
MessagePack is an efficient binary serialization format.It lets you exchange data among multiple languages like JSON. But it‘s faster and smaller.
Small integers are encoded into a single byte, and typical short strings require only one extra byte in addition to the strings themselves.
MessagePack 是一個高效的二進制序列化格式。它讓你像JSON一樣可以在各種語言之間交換數據。但是它比JSON更快、更小。小的整數會被編碼成一個字節,短的字符串僅僅只需要比它的長度多一字節的大小
支持語言:
MessagePack is supported by over 50 programming languages and environments.
MessagePack和JSON壓縮後文件比較
這張圖片是以前MessagePack 官方網站的首頁圖片,數字對比確實很能反映問題,這裏只討論JSON和MessagePack了
為啥會小呢?先來段json:
{“name“:”heyue“,”sex“:”\u7537“,”company“:”sina“,”age“:30}
這個json長度為57字節,但是為了表示這個數據結構(所有標紅色的地方就是他為了表示這個數據結構而不得不添加的),它用了23個字節(就是那些大括號、引號、冒號之類的,他們是白白多出來的)。
MessagePack的核心壓縮方式:
1.true、false 之類的:這些太簡單了,直接給1個字節,(0xc2 表示true,0xc3表示false)
2.不用表示長度的:就是數字之類的,他們天然是定長的,是用一個字節表示後面的內容是什麽東東,比如用(0xcc 表示這後面,是個uint 8,用oxcd表示後面是個uint 16,用 0xca 表示後面的是個float 32).
3.不定長的:比如字符串、數組,類型後面加 1~4個字節,用來存字符串的長度,如果是字符串長度是256以內的,只需要1個字節,MessagePack能存的最長的字符串,是(2^32 -1 ) 最長的4G的字符串大小。
4.ext結構:表示特定的小單元數據。
5.高級結構:MAP結構,就是key=>val 結構的數據,和數組差不多,加1~4個字節表示後面有多少個項。
這個是官方的數據表示結構文檔:https://gist.github.com/frsyuki/5432559
總的來說,MessagePack對數字、多字節字符、數組等都做了很多優化,減少了無用的字符,二進制格式,也保證不用字符化帶來額外的存儲空間的增加,所以MessagePack比JSON小是肯定的,小多少,得看你的數據。如果你用來存英文字符串,那幾乎是沒有區別….
為啥會快呢?
先說說JSON怎麽解析吧,我們開發中一般都用cJSON這個庫,cJSON存儲的時候是采用鏈表存儲的,其訪問方式很像一顆樹。每一個節點可以有兄妹節點,通過next/prev指針來查找,它類似雙向鏈表;每個節點也可以有孩子節點,通過child指針來訪問,進入下一層。問題就是首先,構造這個鏈表的時候,得一個字符一個字符地匹配過去吧,得判斷是不是引號、括號之類的吧…
但是MessagePack 則簡單多了,直接一遍遍歷過去了,從前面的數據頭,就可以知道後面的是什麽數據,指針應該向後移動多少,比JSON的構建鏈表少了很多比較的過程
MessagePack主要用於結構化數據的緩存和存儲:
1.存在Memcache中,因為它比json小,可以省下一些內存來,速度也比json快一些,頁面速度自然快一個檔次。當然,也有一種情況,我在mc中存json,然後直接出來就是頁面可用的json,都不用解析json了(當然這個在實際開發中比較少見)。
2.存在可以持久化的Key-val存儲中。
.NET使用
1.從GIT https://github.com/msgpack/msgpack-cli.git上下載源碼編譯生成DLL
2.示例
using System.IO; using MsgPack.Serialization; namespace MsgPack { class Program { static void Main(string[] args) { CreateMsgPack(); } static void CreateMsgPack() { WriteToFile(); ReadFromFile(); using (var stream = new MemoryStream()) { var serializer = MessagePackSerializer.Create<Person>(); serializer.Pack(stream, CreateIris()); stream.Position = 0; var person = serializer.Unpack(stream); } } static void WriteToFile() { var serializer = MessagePackSerializer.Create<Person>(); using(Stream stream = File.Open(@"C:\Users\Iris\msg.txt", FileMode.Create)) { serializer.Pack(stream, CreateIris()); } } static void ReadFromFile() { var serializer = MessagePackSerializer.Create<Person>(); using (Stream stream = File.Open(@"C:\Users\Iris\msg.txt", FileMode.Open)) { var iris = serializer.Unpack(stream); } } static Person CreateIris() { return new Person { Age = 28, Name = "Iris Classon", FavoriteNumbers = new[] {2,3,4} }; } } public class Person { public string Name { get; set; } public int Age { get; set; } public int[] FavoriteNumbers { get; set; } } }
MessagePack 新型序列化反序列化方案