Non-Blocking I/O with Streams

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:

Three raw HTTP requests multiplexed with stream_select()PHP
<?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.