What it is. The piece that turns your data into
bytes and back. For simple types it does no work at all — it just copies memory, so
the fast path runs at the speed of memcpy itself.
The problem it kills. Serializers like Protobuf or JSON walk every field, allocate, and encode — real CPU on data that's about to be thrown away. Where the layout already matches, Zao charges nothing for it.
For example. In the F1 replay, each telemetry sample carries a packed blob alongside its numeric columns — Zao is what packs and unpacks those at line rate. The throughput run below is real, captured live.
See it move a race ⟶Encode, measured fairly. Zao writes into a caller-owned buffer — zero allocation. MemoryPack and MessagePack get a reused buffer too, so nobody is charged for a throwaway array. Only MemoryPack stays in the same order of magnitude — and it still trails by 1.4–3.6×. MessagePack is 4–60× back; Protobuf and JSON, one to three orders. Lower is better. Zao, MemoryPack and MessagePack here allocate zero bytes; Protobuf and JSON have no zero-alloc path and allocate on every call.
| Message | Zao WriteTo |
MemoryPack reused buf |
MessagePack reused buf |
Protobuf Serialize→[] |
JSON Serialize→[] |
|---|---|---|---|---|---|
| PlayerMoved · 16 B blit | 0.87 ns | 3.11 ns | 42 ns | 141 ns | 305 ns |
| SpawnEntity · + string | 12.5 ns | 26 ns | 58 ns | 143 ns | 282 ns |
| Snapshot · 32 entities | 10.8 ns | 36.7 ns | 491 ns | 1,997 ns | 8,265 ns |
| Snapshot · 1024 entities | 238 ns | 335 ns | 14,249 ns | 63,875 ns | 254,741 ns |
| Inventory · 128-key map | 1.65 µs | 3.18 µs | 2.74 µs | 8.20 µs | 3.49 µs |
Where Zao doesn't win — plainly: it isn't the smallest on the wire; MessagePack's varint packing beats it on small, integer-heavy messages. On decode it's fastest across the board and allocates less for value-type messages (72 B vs 128 B on SpawnEntity), but for collection-heavy messages everyone must build the same array / map / strings, so memory ties. The honest headline is the table above: the fastest zero-allocation encode in .NET.
The table above reads from the rows below: Zao's
*_Encode and the competitors' *_EncodeReuse. Every figure is
BenchmarkDotNet output, unedited.
loading…