← The Dry Stack

Nio

Zero-copy async I/O & messaging — tens of millions of msg/s on one connection, hundreds of millions fanned out; low-microsecond round-trips over loopback.
NOTE: This is using the C# wrapper. Niolib is faster.

What it is. The networking layer the rest of the stack rides on — messages move without copies, straight from one buffer to the wire and back — tens of millions a second on a single connection, hundreds of millions fanned out across many.

The problem it kills. Most systems pay a tax on every message: serialize, copy into the kernel, copy out, deserialize. Where you'd reach for Kafka or a socket library, Nio deletes those copies — the round-trip is microseconds, not milliseconds.

For example. It's what carries replication between nodes in the failover demo — fast enough that a standby stays within one unsealed segment of the leader. The run below is a real harness, captured live.

See it carry a cluster ⟶
Measured against the field · C# wrapper, loopback

Same machine, same loopback, same 64-byte messages — Nio against the libraries you'd actually reach for.

LibraryRound-trip p50Push · 1 connBulk stream
Nio16 µs28M msg/s2.67 GiB/s
raw sockets52 µs28–40M msg/s2.34 GiB/s
NetCoreServer33 µs4.0M msg/s0.39 GiB/s
WebSockets67 µs75K msg/s0.86 GiB/s
gRPC179 µs49K msg/s0.15 GiB/s

Read it straight. Nio matches hand-rolled raw sockets on raw push, beats everything on latency, and leaves the high-level frameworks — gRPC, WebSockets — 100–1000× behind. But raw throughput isn't the headline. What it costs to scale is.

The crowd test · 64 connections at once
12 threads. 206M msg/s. The async-TCP field needs 128 threads — one pair per connection — to push the same load. Nio drains all 64 connections with a handful of poll threads and no locks, at 7× the work per thread.
64 connectionsAggregateOS threadsPer thread
Nio206M msg/s1217M msg/s
raw thread-per-conn299M msg/s1282.3M msg/s
Where it actually matters · scaling to the crowd

Thread-per-connection wins the drag race and loses the war. Push the same test to 1,000 connections:

1,000 connectionsAggregateOS threadsThread memory1s push took
Nio130M msg/s12~12 MB1.0 s
raw thread-per-conn307M msg/s2,000~2 GB7.2 s
Threads & memory — the real advantage
Nio's threads and memory are flat: a fixed pool of poll threads and pre-allocated, GC-free buffers — identical at 64 connections or 10,000. Thread-per-connection pays ~1 MB of stack per thread: at 1,000 connections that's 2,000 threads and ~2 GB of stacks before a single byte of payload, and the scheduler buckles — a one-second push stretched to seven seconds of wall clock. Nio never feels it.

Test bed: AMD Ryzen 9 9950X (16 cores / 32 threads), 64 GB RAM, Windows 11 Pro, .NET 10 Release x64. Loopback (127.0.0.1), via the C# wrapper — the niolib core is faster. 64-byte messages; throughput is time-boxed, median of repeated runs. "raw thread-per-conn" = one OS thread per socket per side, the naïve blocking model. Full harness in samples/Nio.Benchmarks.

Live run · samples/Example
loading…