A couple of images that Grok drew me that explain the issue. Each channel operates on its own strand. Inbound channels (not material here) are bound to a NIC. Outbound channels use boost::asio's default NIC selection. Each channel is on it's own proactor strand, but all share the same network thread pool. So where the software can otherwise easily concurrency across the two independent channels, it's effectively serialized. I also verified that the hardware I/O bus can handle it. Not a problem at all, can handle about 20x more than it's getting.