Performance
Best practices
Create, configure and reuse an instance of MessagePackSerializer rather than recreating it for each use. These objects have a startup cost as they build runtime models for converters that needn't be paid multiple times if you reuse the object. The object is thread-safe. The object is entirely publicly immutable.
Synchronous
The synchronous (de)serialization APIs are the fastest.
Memory allocations are minimal during serialization and deserialization.
We strive for serialization to be allocation free.
Obviously the Serialize<T>(in T?, CancellationToken) method must allocate the byte[]
that is returned to the caller, but such allocations can be avoided by using any of the other Serialize overloads which allows serializing to pooled buffers.
Asynchronous
The asynchronous APIs are slower (ranging from slightly to dramatically slower) but reduce total memory pressure because the entire serialized representation does not tend to need to be in memory at once.
Memory pressure improvements are likely, but not guaranteed, because there are certain atomic values that must be in memory to be deserialized.
For example a very long string or byte[]
buffer will have to be fully in memory in its msgpack form at the same time as the deserialized or original value itself.
Async (de)serialization tends to have a few object allocations during the operation.
Custom converters
The built-in converters in this library go to great lengths to optimize performance, including avoiding encoding/decoding strings for property names repeatedly. These optimizations lead to less readable and maintainable converters, which is fine for this library where perf should be great by default. Custom converters however are less likely to be highly tuned for performance. For this reason, it can be a good idea to leverage the automatic converters for your data types wherever possible.
Comparison to MessagePack-CSharp
Perf isn't everything, but it can be important in some scenarios. Nerdbank.MessagePack is very fast, but not quite as fast as MessagePack-CSharp v3 with source generation turned on.
Features and ease of use are also important. Nerdbank.MessagePack is much simpler to use, and comes loaded with features that MessagePack-CSharp does not have. Nerdbank.MessagePack also reliably works in AOT environments, while MessagePack-CSharp does not.
This library has superior startup performance compared to MessagePack-CSharp due to not relying on reflection and Ref.Emit. Throughput performance is on par with MessagePack-CSharp.
When using AOT source generation from MessagePack-CSharp and objects serialized with maps (as opposed to arrays), MessagePack-CSharp is slightly faster at deserialization.
In the perf comparisons below, the following legend applies
Library alias | Full name |
---|---|
NB.MessagePack | Nerdbank.MessagePack (this library) |
MsgPack-CS | MessagePack-CSharp |
Newtonsoft | Newtonsoft.Json |
STJ | System.Text.Json |
Object serialization comparisons
Each stacked bar shows the time taken to serialize and deserialize an object. The two times added together represent round-trip time.
In messagepack, an object may be serialized as a map of property names and values, or as an array of just values.
Some libraries are absent from some comparisons because they don't support a particular format.
xychart-beta
x-axis "Libraries" ["NB.MessagePack", "MsgPack-CS", "STJ", "Newtonsoft"]
y-axis "Time (ns)" 0 --> 1100
title "object as map"
bar "Serialize+Deserialize" [288.68,235.88,564.09,1072.37]
bar "Serialize" [91.84,86.31,107.03,405.12]
xychart-beta
x-axis "Libraries" ["NB.MessagePack", "MsgPack-CS", "STJ", "Newtonsoft"]
y-axis "Allocated (bytes)" 0 --> 4200
title "object as map"
bar "Serialize+Deserialize" [80,80,208,4112]
bar "Serialize" [0,0,128,1424]
xychart-beta
x-axis "Libraries" ["NB.MessagePack", "MsgPack-CS"]
y-axis "Time (ns)" 0 --> 300
title "object as array"
bar "Serialize+Deserialize" [222.75,200.18]
bar "Serialize" [103.15,79.75]
xychart-beta
x-axis "Libraries" ["NB.MessagePack", "MsgPack-CS"]
y-axis "Allocated (bytes)" 0 --> 100
title "object as array"
bar "Serialize+Deserialize" [80,80]
bar "Serialize" [0,0]