PHP 8.5 vs Node.js vs Go vs Python: I/O Performance Under Real Database Load (2026)

Earlier this year, we published a comprehensive CPU‑intensive cross‑language benchmark that put PHP 8.5 (with JIT on/off), Node.js 22, Go 1.24, and Python 3.12 head‑to‑head. The results were clear: Go dominated CPU‑bound tasks, Node.js held its own, and PHP with JIT landed in the middle. But a recurring question from readers was: “What about I/O? My app spends most of its time waiting for the database, not crunching numbers.”

That’s exactly what we benchmarked this time. We took the same four languages and added PHP 8.5 + Swoole with coroutines and connection pooling, then tested them under real database I/O latency – 50ms and 200ms SELECT SLEEP() delays. The results are dramatically different from the CPU benchmark, and they may change how you think about PHP in high‑I/O environments.


🧪 Test Environment

  • Server: 4 vCPU, 8 GB RAM, Ubuntu 22.04
  • Database: MySQL 8.4 (same host, max_connections=151)
  • PHP: 8.5.7 with OPcache + JIT tracing, buffer 128M
  • Swoole: 6.2.1, 20 workers, coroutine + PDO with connection pooling
  • Node.js: 22.x, connection pool size 20
  • Go: 1.24.x, database/sql with connection pool size 20
  • Python: 3.12.x, aiomysql with connection pool size 20
  • Load generator: ab -c 100 -t 60 (100 concurrent connections, 60 seconds), 3 runs per configuration

Business logic (identical across all languages):

  • CPU: 1000 iterations of sqrt($i) (same as the CPU benchmark)
  • I/O: One database query – either SELECT 1 (baseline) or SELECT SLEEP(0.05) / SELECT SLEEP(0.2)

Worker/connection configuration:

  • PHP‑FPM: 20 static workers
  • Swoole: 20 worker processes with coroutine support
  • Node.js: 20 connection pool
  • Go: 20 max open connections
  • Python: 20 max connection pool

All services returned identical compute values (21065.833110879048), confirming the business logic executed consistently across all languages.


📊 Benchmark Results

50ms Database I/O Latency

Language / RuntimeAvg RPSP99 (ms)
PHP + Swoole1,91262
Node.js393256
Go394914
Python393461
PHP‑FPM388264
Bar chart comparing RPS of PHP-FPM, Swoole, Node.js, Go, and Python under 50ms database I/O latency
Figure 1: RPS comparison at 50ms I/O latency – Swoole leads with 1,912 RPS.

Swoole achieves 4.9× higher RPS than the next best performer under 50ms I/O latency.

200ms Database I/O Latency

Language / RuntimeAvg RPSP99 (ms)
PHP + Swoole495208
Go1082,001
Node.js991,008
Python992,600
PHP‑FPM991,016
Bar chart comparing RPS of PHP-FPM, Swoole, Node.js, Go, and Python under 200ms database I/O latency
Figure 2: RPS comparison at 200ms I/O latency – Swoole maintains 5× higher throughput.

At 200ms latency, Swoole maintains 5× higher throughput than all other runtimes.


🔍 Analysis

Bar chart comparing P99 latency of PHP-FPM, Swoole, Node.js, Go, and Python under 50ms and 200ms I/O latency
Figure 3: P99 latency comparison – Swoole has the lowest tail latency in both scenarios.

Why Does Swoole Dominate I/O?

The answer lies in coroutines. Under traditional PHP‑FPM, each worker process blocks entirely while waiting for a database query to complete. With 20 workers and a 50ms query, the theoretical maximum is roughly 1000ms / 50ms × 20 = 400 RPS – and PHP‑FPM hits ~388 RPS, right at that limit.

Swoole, however, uses coroutines that yield during I/O waits, allowing a single worker to handle multiple concurrent requests. With 20 workers and coroutine concurrency, Swoole achieves ~1,912 RPS at 50ms latency – roughly 4.9× higher than the synchronous limit.

At 200ms latency, the gap widens even further. While other runtimes hover around the theoretical limit of ~100 RPS (5 requests/second × 20 workers), Swoole maintains ~495 RPS, demonstrating that coroutines effectively multiply the concurrency of each worker.

Why Is Go’s P99 Latency So High?

Go’s average RPS is competitive (~394 at 50ms), but its P99 latency spikes to 914ms – far higher than Node.js (256ms) and Python (461ms). This suggests that while most requests complete quickly, a small fraction experience significant delays.

Possible explanations:

  • Connection pool contention: Go’s database/sql connection pool may experience contention under sustained load.
  • Garbage collection pauses: Go’s GC can introduce occasional latency spikes.
  • MySQL driver overhead: The go-sql-driver/mysql driver may behave differently under load.

Why Is PHP‑FPM Competitive at 50ms?

At 50ms latency, PHP‑FPM achieves ~388 RPS – nearly identical to Node.js, Go, and Python. This is because all synchronous runtimes are bounded by the same limit: the number of workers multiplied by the maximum throughput per worker. Under pure I/O wait, the language runtime matters less than the concurrency model.

The real separation happens when you introduce coroutines (Swoole) or truly non‑blocking I/O (Node.js’s event loop, Go’s goroutines). But even Node.js and Go, despite their async models, couldn’t match Swoole’s coroutine efficiency in this test.


📊 Visual Comparison

MetricPHP‑FPMPHP+SwooleNode.jsGoPython
50ms RPS3881,912393394393
50ms P9926462256914461
200ms RPS994959910899
200ms P991,0162081,0082,0012,600

🎯 Recommendations

Choose Swoole if…

  • Your application is I/O‑heavy – database queries, API calls, Redis, or any external network requests.
  • You want to stay in PHP but need Node.js‑ or Go‑level I/O performance.
  • You’re willing to invest in learning coroutine‑safe programming patterns.

Choose Node.js if…

  • You need a mature async ecosystem with excellent library support.
  • Your team is already comfortable with JavaScript/TypeScript.
  • You want consistent performance without coroutine‑specific pitfalls.

Choose Go if…

  • You need predictable CPU performance and can tolerate occasional P99 latency spikes (or are willing to profile and tune).
  • You’re building a microservice where goroutines and channels are a natural fit.
  • You value static typing and fast compilation.

Choose Python if…

  • You’re in a data‑science or ML‑adjacent environment.
  • You need async I/O and are comfortable with asyncio and async database drivers.
  • Performance is not your primary constraint.

Stick with PHP‑FPM if…

  • Your application is CPU‑bound rather than I/O‑bound.
  • You’re on shared hosting or a traditional LAMP stack.
  • You don’t want to introduce additional complexity.

🔬 Key Takeaways

  • Coroutines change everything for PHP. Swoole transforms PHP from a synchronous, blocking language into a concurrency powerhouse that rivals – and in this test, exceeds – Node.js and Go for I/O‑intensive workloads.
  • Synchronous runtimes converge under I/O load. PHP‑FPM, Node.js, Go, and Python all delivered ~390 RPS at 50ms latency.
  • Swoole’s advantage grows with latency. At 200ms, Swoole is ~5× faster than all others.
  • Go’s P99 latency requires attention. While Go’s average RPS is solid, its tail latency suggests tuning may be needed for production.
  • The right tool depends on your bottleneck. CPU‑bound? Go leads. I/O‑bound? Swoole is a game‑changer.

📁 Reproducibility

All test scripts, configuration files, and raw ab outputs are available in the GitHub repository.

To replicate:

git clone https://github.com/phpbenchlab/cross-lang-io-benchmark.git
cd cross-lang-io-benchmark
# Follow the README to start all services and run the benchmark script

We’ve included:

  • PHP‑FPM with Nginx configuration
  • PHP + Swoole with coroutine and connection pooling
  • Node.js with mysql2 connection pool
  • Go with database/sql and connection pool
  • Python with aiomysql async connection pool
  • Full ab benchmark script
  • Raw result files

🧵 Final Words

This benchmark tells a clear story: for I/O‑intensive PHP applications, Swoole is a game‑changer. It delivers performance that rivals – and in this test, surpasses – Node.js and Go, while keeping you in the PHP ecosystem. If your application spends most of its time waiting for databases or external APIs, Swoole deserves a serious look.

At the same time, don’t dismiss Go or Node.js – they have their own strengths in CPU‑bound tasks, developer ergonomics, and ecosystem maturity. The key takeaway is that the best language for your project depends on your workload’s bottleneck.

Have you tried Swoole in production? Or migrated from Node.js/Go to PHP for I/O performance? Share your experience in the comments!

Published on June 29, 2026 – PHP 8.5 I/O cross‑language benchmark.

Leave a Comment