Skip to content
Tech News
← Back to articles

Zero-copy in Go: sendfile, splice, and the cost of io.Copy

read original more articles

A small file-serving service of mine slowed to a crawl one afternoon after a “harmless” middleware change. CPU on the server box doubled, throughput roughly halved. The diff was a single line: instead of handing a *os.File to io.Copy , somebody had wrapped it in a tiny logging reader to count bytes.

That one wrap quietly turned off sendfile(2) .

This post is about that fast path: what Go does for you for free, how to see it actually fire, and the surprisingly easy ways to lose it.

The setup

Linux 6.6 / Ubuntu 24.04 (WSL2), AMD Ryzen 5 9600X, 16 GiB RAM

Go 1.22.12

512 MiB random-bytes file, page cache warm

Every benchmark below serves the same big.bin file over plain TCP to a Go client on the same machine. Server pinned to CPU 0, client to CPU 1, so we can read /usr/bin/time server-side and compare apples to apples. Syscall counts come from a vanilla strace -c -e trace=read,write,sendfile,splice .

What sendfile actually does

A normal “send this file” looks like this:

... continue reading