Software · 06 / 06 · Java 21 · Python · Kafka
Streaming Consumer Benchmark
The same fan-out server written twice, Java 21 virtual threads and Python asyncio, measured by one harness up to 20,000 connections.
- Java 21
- Virtual threads
- Python asyncio
- uvloop
- Kafka
- JMH
- Docker
Why I built this
Teams pick Python asyncio or Java for high-concurrency services mostly on opinion. Java 21's virtual threads changed that trade-off: simple blocking code that can hold tens of thousands of connections. The choice decides how many servers you pay for and how fast users get their data.
Python asyncio or Java 21 virtual threads: which should a team pick for a service holding thousands of connections? People argue for both. I wanted numbers instead, even if they went against Python, the language I use most.
What I built
The hot path of my streaming platform, Kafka in and thousands of TCP sockets out, written twice: Java 21 with one virtual thread per connection, and Python asyncio on uvloop.
Both pass the same conformance suite against real Kafka, and one load harness drives them. Every run starts from a cold container, discards the warm-up window and audits every sequence number.
How it works
Same protocol, same harness, same 2 CPUs and 1 GiB per server. Only the concurrency model changes.
Measured
- Up to 5,000 connections
- Both about 2 ms p50. Java p99 4-5 ms, Python 5-10 ms
- 10,000 connections
- Java p99 8 ms. Python on one process: p99 253 ms (one core at 100%)
- 20,000 connections
- Java with 2 dispatch threads: p50 2.5 ms. Python on 2 processes: p50 184 ms
- Memory per connection
- Java about 28 KiB (+190 MiB JVM). Python about 12 KiB (+45 MiB)



