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

  • 3068
  • 0
  • 2026-01-08

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

           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(),
                   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(),
                   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>(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>(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 給的數據都不一定正確,不如自己實測看看。

--

本文原文首發於個人部落格: 實際測了 MessagePack:10,000 筆資料下,比 JSON.NET 快三倍

--

---

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