In PHP's shared-nothing model (How a Request Becomes a Page), a PHP-FPM worker runs one request top to bottom and then forgets everything. Every call blocks until its answer is in, and concurrency comes from running many workers (FPM Pools). That is simple and robust, but a request with several independent waits pays for each in turn. The demos call a local endpoint on port 8323 that sleeps 0.5 s and echoes its id as JSON, served by FrankenPHP 912,500 's threaded server (FrankenPHP and Worker Mode): php -S with PHP_CLI_SERVER_WORKERS=8 took 1.51 s for six concurrent requests, queuing them per worker.
<?php
$t0 = hrtime(true);
foreach ([1, 2, 3] as $id) {
$json = file_get_contents("http://127.0.0.1:8323/?id=$id"); // waits 0.5 s each time
printf("%.2f s %s\n", (hrtime(true) - $t0) / 1e9, $json);
}0.50 s {"id":1}
1.01 s {"id":2}
1.51 s {"id":3}
An event loop keeps one thread but never idles on one socket: it asks the kernel (select, epoll) which connection has data and runs the code waiting for it.