Busy Loop Discussion
CMCDragonkai opened this issue · 5 comments
Currently block
relies on a while call to check if a flag has changed in order to implement async blocking. This may result in a busy loop wasting CPU cycles.
There are alternatives to doing this. One can use a flock and block on the lock, this makes use of the OS locking mechanism to prevent busy looping. Another way is to use one of the process control extensions: http://php.net/manual/en/refs.fileprocess.process.php
While the above 2 work. The former needs a lock file (which is not always readily available), the latter requires installing extensions which is not always available.
A third way is to use http://php.net/manual/en/function.stream-select.php however this ideally should be paired up with the unix pipe call. But there doesn't seem to be a PHP wrapper for the anonymous pipe call, a discussion was formed here: https://bugs.php.net/bug.php?id=60896
However an alternative is real sockets which is provided by native PHP: http://php.net/manual/en/function.socket-create-pair.php
and http://php.net/manual/en/function.socket-select.php
So combining the 2 together, we can create a non-busy loop for the async to sync conversion.
Here's an example:
$sockets = [];
socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets);
socket_write($sockets[1], 1, 1); // this one would be in the async then
$r = [$sockets[0]];
$w = null;
$e = null;
socket_select($r, $w, $e, null, null);
socket_close($sockets[0]);
socket_close($sockets[1]);
On my computer, it shows 0% CPU usage. I believe should work on all OSes. However the PHP docs doesn't mention whether AF_UNIX is available for Windows, so AF_INET can also be used. Also the docs doesn't seem to mention how the AF_UNIX socket is stored on the filesystem, it seems automatic.
If $loop->run();
blocks entirely, then the while loop shouldn't be a problem, in which case the above is unnecessary.
Thanks for your in-depth analysis!
Currently block relies on a while call to check if a flag has changed in order to implement async blocking. This may result in a busy loop wasting CPU cycles.
I may be missing something obvious, but the problem you're having appears a bit unclear to me, i.e. what are we actually tying to fix here and when does this happen? :-)
My tests show that loop->run() does in fact block so it's not necessary to perform the tricks I stated above.
Yeah, this would be expected behavior
Other than that, does this solve this issue or do you feel there's something that needs to be done here?