Giter Club home page Giter Club logo

Comments (9)

WyriHaximus avatar WyriHaximus commented on May 21, 2024 1

Forgotten async() call forces SimpleFiber::suspend() to call Loop::run()

self::$scheduler = new \Fiber(static fn() => Loop::run());

But if Loop::run() is already called before await() is called, then this causes various problems.
Another example

<?php

use React\EventLoop\Loop;
use React\Promise\Deferred;

use function React\Async\await;

require __DIR__  . '/vendor/autoload.php';

Loop::futureTick(/* missed await */ function () {
	$deferred = new Deferred();
	Loop::addTimer(0, static fn() => $deferred->resolve());
	await($deferred->promise());
});

Loop::futureTick((static fn() => 0));
PHP Fatal error:  Uncaught RuntimeException: Can't shift from an empty datastructure in /vendor/react/event-loop/src/Tick/FutureTickQueue.php:46
Stack trace:
#0 /vendor/react/event-loop/src/Tick/FutureTickQueue.php(46): SplQueue->dequeue()
#1 /vendor/react/event-loop/src/ExtEventLoop.php(203): React\EventLoop\Tick\FutureTickQueue->tick()
#2 /vendor/react/event-loop/src/Loop.php(55): React\EventLoop\ExtEventLoop->run()
#3 [internal function]: React\EventLoop\Loop::React\EventLoop\{closure}()
#4 {main}
  thrown in /vendor/react/event-loop/src/Tick/FutureTickQueue.php on line 46

As a result, we do not know the problem file and line. It's very easy to miss async() in future code.

We MIGHT always wrap loop handers in an async() call in the future. For now, you have to do this yourself, and yes that means you might miss one.

But I'll also open a PR to test this package against all event loops we support because honestly I only develop and tested it against ext-uv. Also @clue has looked into if we still perse need the future ticks and we might drop them from the implementation. I'll also PR your example as a test, if it's not already in there in a maybe slightly different way.

Maybe just throw an exception instead of calling Loop::run() ?

Because that Fiber constructor argument triggers when the main Fiber starts.

from async.

clue avatar clue commented on May 21, 2024 1

Thanks, there is no problem with async(). Does this mean that any function that contains await() should be wrapped with async() ?

Excellent input! The await() function can indeed be considered "blocking", so if you're using it from an event loop timer, event listener, or promise callback, you should always wrap it in an async() function. I've just filed #26 to add documentation for this behavior.

Technically, we could also wrap this automatically for each callback, but this incurs a significant overhead. This is especially true as we would have to do this for each callback even if it does not use await() internally, because there's no way to tell from the outside.

At the moment, explicitly using async() in these cases instead seems like a reasonable compromise between ease of use and performance. This is still an early development version and I'm curious to see how the ecosystem and performance considerations evolve over time! 👍

from async.

WyriHaximus avatar WyriHaximus commented on May 21, 2024

Which version of this package are you using?

from async.

Provoker avatar Provoker commented on May 21, 2024

@WyriHaximus,
react/async: dev-main (ff11a7a)
react/event-loop: v1.2.0

Tested on PHP 8.1.0 and PHP 8.1.1

from async.

WyriHaximus avatar WyriHaximus commented on May 21, 2024

Here you tried:

<?php

use React\EventLoop\Loop;
use React\Promise\Deferred;
use function React\Async\async;
use function React\Async\await;

require __DIR__  . '/vendor/autoload.php';

Loop::addTimer(0, async(function () {
	$deferred = new Deferred();
	Loop::addTimer(0, static fn() => $deferred->resolve());
	await($deferred->promise());
}));

Or using https://github.com/reactphp/promise-timer#sleep

<?php

use React\EventLoop\Loop;
use React\Promise\Deferred;
use function React\Async\async;
use function React\Async\await;
use React\Promise\Timer\sleep;

require __DIR__  . '/vendor/autoload.php';

Loop::addTimer(0, async(function () {
	await(sleep(0));
}));

from async.

Provoker avatar Provoker commented on May 21, 2024

Thanks, there is no problem with async().
Does this mean that any function that contains await() should be wrapped with async() ?

from async.

Provoker avatar Provoker commented on May 21, 2024

Forgotten async() call forces SimpleFiber::suspend() to call Loop::run()

self::$scheduler = new \Fiber(static fn() => Loop::run());

But if Loop::run() is already called before await() is called, then this causes various problems.

Another example

<?php

use React\EventLoop\Loop;
use React\Promise\Deferred;

use function React\Async\await;

require __DIR__  . '/vendor/autoload.php';

Loop::futureTick(/* missed await */ function () {
	$deferred = new Deferred();
	Loop::addTimer(0, static fn() => $deferred->resolve());
	await($deferred->promise());
});

Loop::futureTick((static fn() => 0));
PHP Fatal error:  Uncaught RuntimeException: Can't shift from an empty datastructure in /vendor/react/event-loop/src/Tick/FutureTickQueue.php:46
Stack trace:
#0 /vendor/react/event-loop/src/Tick/FutureTickQueue.php(46): SplQueue->dequeue()
#1 /vendor/react/event-loop/src/ExtEventLoop.php(203): React\EventLoop\Tick\FutureTickQueue->tick()
#2 /vendor/react/event-loop/src/Loop.php(55): React\EventLoop\ExtEventLoop->run()
#3 [internal function]: React\EventLoop\Loop::React\EventLoop\{closure}()
#4 {main}
  thrown in /vendor/react/event-loop/src/Tick/FutureTickQueue.php on line 46

As a result, we do not know the problem file and line. It's very easy to miss async() in future code.

Maybe just throw an exception instead of calling Loop::run() ?

from async.

WyriHaximus avatar WyriHaximus commented on May 21, 2024

@Provoker Which version of ext-event are you running?

from async.

Provoker avatar Provoker commented on May 21, 2024

@WyriHaximus, Latest stable from pecl

Sockets support => enabled
Debug support => disabled
Extra functionality support including HTTP, DNS, and RPC => enabled
OpenSSL support => enabled
Thread safety support => disabled
Extension version => 3.0.6
libevent2 headers version => 2.0.21-stable

from async.

Related Issues (14)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.