2026-01-06

[C#] 實際測了 MessagePack:10,000 筆資料下,比 JSON.NET 快三倍

MessagePack 其實一直都聽到這名詞,但是因為在這 JSON 當到的現在比較少處理這東西,所導致我聽到很久了

但是也沒有實際去測試他,最近測試一下似乎蠻好用的


MessagePack 是一種以 binary 為基礎的序列化格式,設計目標很單純

讓機器之間交換資料更快、更小。它不像 JSON 追求人類可讀性,而是用固定順序與型別直接寫入位元資料,省略字串解析與中間物件建立的成本

在資料量大、結構固定、需要頻繁序列化與反序列化的情境下,MessagePack 往往能明顯降低 CPU 與 GC 壓力,這也是我這次會實際測它效能的原因

1. 我測試環境是 .NET 10 ,一樣沒有內建,請先到 nuget 下面去下載 https://www.nuget.org/packages/messagepack

2. 資料模型,因為我要測試,所以我得先設計一個有點點複雜的模型

[MessagePackObject] public sealed class User { [Key(0)] public int Id { get; set; } [Key(1)] public string Name { get; set; } = ""; [Key(2)] public List<User> Friends { get; set; } = new(); [Key(3)] public int Age { get; set; } [Key(4)] public string Alias { get; set; } = ""; [Key(5)] public decimal Salary { get; set; } [Key(6)] public DateTime Birth { get; set; } }

3. 這時候就是來測試他跟我常用的 JSON.NET 拚速度了,這邊我直接給程式碼

var testData = new List<User>(); for (var i = 1; i <= 10000; i++) { var main = new User { Id = i, Name = $"當麻 {i}", Age = 20 + (i % 30), Alias = (i % 2 == 0) ? $"Alias_{i}" : null, Friends = new List<User>(), Salary = i * i , Birth=new DateTime(1970,1,1).AddDays(i) }; main.Friends.Add(new User { Id = i, Name = $"Donma Friend {i}", Age = 20 + (i % 30), Alias = (i % 2 == 0) ? $"朋友暱稱_{i}" : null, Friends = new List<User>(), Salary = i * 10, Birth = new DateTime(1990, 1, 1).AddDays(i) }); testData.Add(main); } Console.WriteLine("-- MessagePack 測試 --"); var sp = new Stopwatch(); sp.Start(); //序列化 to MessagePack byte[] messagePackBytes = MessagePackSerializer.Serialize(testData, MessagePackSerializerOptions.Standard); Console.WriteLine("MessagePack 序列化時間:" + sp.Elapsed); File.WriteAllBytes(AppDomain.CurrentDomain.BaseDirectory + "data.messagepack", messagePackBytes); string base64 = Convert.ToBase64String(messagePackBytes); File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "data.base64", base64); sp.Restart(); // MessagePack 反序列化 var testDataDeserialize = MessagePackSerializer.Deserialize<List<User>>(messagePackBytes, MessagePackSerializerOptions.Standard); Console.WriteLine("MessagePack 反序列化時間:" + sp.Elapsed); Console.WriteLine($"Data Count:" + testDataDeserialize.Count + ", 測試一筆資料:" + testDataDeserialize[999].Name+","+ testDataDeserialize[999].Salary+","+ testDataDeserialize[999].Birth.ToString("yyyy-MM-dd"+","+ testDataDeserialize[999].Friends.Count)); Console.WriteLine("-- JSON.NET 測試 --"); //JSON 序列化 sp.Restart(); var testJson = JsonConvert.SerializeObject(testData); Console.WriteLine("JSON.NET 序列化時間:" + sp.Elapsed); File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "data.json", testJson); //JSON 反序列化 sp.Restart(); var testDataDeserializeJSON = JsonConvert.DeserializeObject<List<User>>(testJson); Console.WriteLine("JSON.NET 反序列化時間:" + sp.Elapsed); Console.WriteLine($"Data Count:" + testDataDeserializeJSON.Count+ ", 測試一筆資料:" + testDataDeserializeJSON[999].Name + "," + testDataDeserializeJSON[999].Salary + "," + testDataDeserializeJSON[999].Birth.ToString("yyyy-MM-dd" + "," + testDataDeserializeJSON[999].Friends.Count));


4.測試結果

-- MessagePack 測試 -- MessagePack 序列化時間:00:00:00.1428397 MessagePack 反序列化時間:00:00:00.0652231 Data Count:10000, 測試一筆資料:當麻 1000,1000000,1972-09-27,1 -- JSON.NET 測試 -- JSON.NET 序列化時間:00:00:00.2635574 JSON.NET 反序列化時間:00:00:00.2995923 Data Count:10000, 測試一筆資料:當麻 1000,1000000.0,1972-09-27,1


先說結論跟注意事項,顯而易見的確速度有非常"顯著" 的改變,但是在第二步的時候

Key(index) 這部分,這需要完全對應,如果你對應錯誤則就會返序列化失敗這點要非常注意

畢竟這世界就是有一好沒二好,你享受速度就是必須要有些妥協,而且變成二進位後可讀性也減少了,這邊,我多紀錄一下他們存檔後的檔案大小

讓體積跟大小具象化

data.base64 1,088 KB

data.json 2,426 KB

data.messagepack 816 KB

所以檔案大小有非常非常顯著的差異,即使變成 base64 也還是小了 50% 

這次測試數據到這邊,畢竟有時候問 AI ,AI 給的數據都不一定正確,不如自己實測看看。



--

The bug existed in all possible states. Until I ran the code.

如果這篇文章有幫助到您幫我分享一下,讓我有寫下去的動力...