G
G
Grigory Vasilkov2019-04-26 15:48:50
PHP
Grigory Vasilkov, 2019-04-26 15:48:50

How to implement async with ReactPHP on Windows?

If I understand the idea correctly - a server process is raised that can execute code asynchronously
I run sleep(3), sleep(2), sleep(1) asynchronously
I should see output 1-2-3, and wait 3 seconds because . the browser is waiting for a response
Instead of waiting 6 seconds and 3-2-1, as if everything is working synchronously Here is the code that does not work, can you tell me what I'm doing
wrong
..
Is it because of Windows?
It's just that if this thing only works on Linux, then there is pthreads.so in it which works fine and what's the point of this wrapper?
By the way, pthreads.dll also works in the Windows CLI (but only in the console) - I ran the script with this plug-in and it still took 6 seconds.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
F
Flying, 2020-01-14
@gzhegow

No, it's not because of Windows, the problem is in your code, although it's not as obvious as it seems, I had to tinker to find the answer.
In short, the main problem is in the use sleep()for delay emulation. Indeed, unlike the same setTimeout()in JavaScript, which natively uses the event loop, and therefore is asynchronous, sleep()in PHP it is just a delay i.e. blocking operation. Your code couldn't continue until it ran sleep(), hence the execution sequence, which is in fact almost synchronous.
To get an asynchronous delay, you had to use LoopInterface::addTimer() , then the code starts working as it should.
A slightly modified version of your code, with formatting and delay output, gave:

[3] 3 sec
[2] 5 sec
[1] 6 sec

both on Windows and Linux.
If you use the option below, then the result becomes expected, both on Windows and on Linux:
[1] 1 sec
[2] 2 sec
[3] 3 sec

Below is the code that gives the correct result, I did not change the structure much, although it can be simplified.
<?php

use React\EventLoop\Factory;
use React\Http\Response;
use React\Http\Server;

require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/async.php';

$loop = Factory::create();
$socket = new \React\Socket\Server($argv[1] ?? '0.0.0.0:0', $loop);

$server = new Server(static function () use ($loop) {
    $test = new Async($loop);
    return $test->run()->then(static function () use ($test) {
        return new Response(
            200,
            ['Content-Type' => 'text/plain'],
            (string)$test
        );
    });
});
$server->listen($socket);

echo 'Listening on ' . str_replace('tcp:', 'http:', $socket->getAddress()) . PHP_EOL;
$loop->run();

<?php

use React\EventLoop\LoopInterface;
use React\Promise\PromiseInterface;

class Async
{
    protected $_stdout;
    /**
     * @var LoopInterface
     */
    private $loop;

    /**
     * @param LoopInterface $loop
     */
    public function __construct(LoopInterface $loop)
    {
        $this->loop = $loop;
    }

    public function __toString()
    {
        return $this->_stdout;
    }

    public function run(): PromiseInterface
    {
        $start = time();
        $handler = function ($x) use ($start) {
            $this->_stdout .= sprintf("[%d] %d sec\n", $x, time() - $start);
        };
        return React\Promise\all([
            $this->asyncAction(3)->then($handler),
            $this->asyncAction(2)->then($handler),
            $this->asyncAction(1)->then($handler),
        ]);
    }

    protected function asyncAction(int $sleep = 0): PromiseInterface
    {
        return new React\Promise\Promise(function ($resolve, $reject) use ($sleep) {
            $this->action($sleep, static function ($e, $result) use ($resolve, $reject) {
                if ($e) {
                    $reject($e);
                } else {
                    $resolve($result);
                }
            });
        });
    }

    protected function action(int $sleep, callable $callback): void
    {
        $this->loop->addTimer($sleep, static function () use ($sleep, $callback) {
            $callback(null, $sleep);
        });
    }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question