Benchmarks¶
The checked-in run compares h2corn with uvicorn, hypercorn, and gunicorn on the same Starlette application across HTTP/1.1, HTTP/2, Unix sockets, static files, streaming, and WebSockets. It used Python 3.14.3 on Linux 6.18.38, x86_64, and an AMD Ryzen 9 5950X.
The load generator connects directly to each server with no reverse proxy or TLS terminator. Trials are 2 seconds of warmup followed by 10 seconds of load, with 3-9 cold starts, rotated server order, and no CPU pinning. Reported values are medians with the observed range. Each trial checks status, content type, body, and worker readiness; a competitor that cannot serve a scenario is excluded with its reason, while an h2corn failure stops the run.
The run uses loopback and records peak proportional set size (PSS) across the supervisor and workers. The harness requirements, optional network profile, smoke command, raw per-run output, and publish rules are in bench/README.md.
HTTP/1 GET¶
HTTP/1 GET over Unix domain sockets¶
HTTP/2 GET, multiplexed¶
Ten concurrent streams share a connection in this workload. Hypercorn returned connection errors and is excluded from the comparison.
HTTP/2 GET¶
The direct HTTP/2 workload includes h2corn and Hypercorn; Uvicorn and Gunicorn provide no HTTP/2 listener in this harness.
Static file¶
The workload serves a 128 KiB Starlette FileResponse, using the ASGI http.response.pathsend extension where supported.
Streaming download¶
The workload yields eight 16 KiB chunks.
Streaming POST¶
The workload uploads a 1 KiB body from 1,000 concurrent clients and receives a chunked response. Gunicorn timed out 281 requests in the single-worker HTTP/1 scenario and is excluded.
WebSocket¶
Reruns, focused A/B measurements, and the complete non-publishing harness command are documented in bench/README.md. The workload excludes proxy and TLS behavior, HTTP/3, browser behavior, cold-start latency, failure recovery, and applications other than the tested Starlette app.