stream_set_blocking($s, false) makes fread() return whatever has arrived instead of waiting. stream_select() sleeps in the kernel until at least one stream is ready, then trims its arrays to the ready ones. Together they run three HTTP requests at once:
<?php
$t0 = hrtime(true);
foreach ([1, 2, 3] as $id) {
$open[$id] = stream_socket_client('tcp://127.0.0.1:8323');
fwrite($open[$id], "GET /?id=$id HTTP/1.0\r\nHost: localhost\r\n\r\n");
stream_set_blocking($open[$id], false); // fread() returns what has arrived, maybe ''
$body[$id] = '';
}
while ($open) {
$read = $open; // stream_select() trims its arguments
stream_select($read, $write, $except, 5); // sleep until a socket is readable
foreach ($read as $id => $s) { // keys survive, so $id names the request
$body[$id] .= fread($s, 8192);
if (!feof($s)) continue;
unset($open[$id]);
printf("%.2f s %s\n", (hrtime(true) - $t0) / 1e9, strstr($body[$id], '{'));
}
}Output
0.50 s {"id":1}
0.50 s {"id":2}
0.50 s {"id":3}All three answers arrived at 0.50 s, against 1.51 s when blocking. select() scans every descriptor per call and stops at 1,024, so ReactPHP switches to ext-ev, ext-event or ext-uv when installed. The connect here still blocks; libraries use STREAM_CLIENT_ASYNC_CONNECT.