From 059d75a17c2f252c5fe1b5217c91866089c09ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Wed, 26 Apr 2017 11:48:27 +0200 Subject: [PATCH 1/2] Tick callback receives no arguments, remove cyclic dependency This can easily be replaced by using closure binding as documented. --- README.md | 29 ++++++++++++++--- examples/91-benchmark-ticks.php | 2 +- examples/93-benchmark-ticks-delay.php | 2 +- examples/94-benchmark-timers-delay.php | 2 +- src/ExtEventLoop.php | 2 +- src/LibEvLoop.php | 2 +- src/LibEventLoop.php | 2 +- src/LoopInterface.php | 43 +++++++++++++++++++++++--- src/StreamSelectLoop.php | 2 +- src/Tick/FutureTickQueue.php | 11 ++----- tests/AbstractLoopTest.php | 3 +- 11 files changed, 74 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index d67ad534..19e86181 100644 --- a/README.md +++ b/README.md @@ -126,12 +126,33 @@ schedule a callback to be invoked on a future tick of the event loop. This works very much similar to timers with an interval of zero seconds, but does not require the overhead of scheduling a timer queue. -Unlike timers, callbacks are guaranteed to be executed in the order they -are enqueued. +The tick callback function MUST be able to accept zero parameters. + +The tick callback function MUST NOT throw an `Exception`. +The return value of the tick callback function will be ignored and has +no effect, so for performance reasons you're recommended to not return +any excessive data structures. + +If you want to access any variables within your callback function, you +can bind arbitrary data to a callback closure like this: + +```php +function hello(LoopInterface $loop, $name) +{ + $loop->futureTick(function () use ($name) { + echo "hello $name\n"; + }); +} + +hello('Tester'); +``` + +Unlike timers, tick callbacks are guaranteed to be executed in the order +they are enqueued. Also, once a callback is enqueued, there's no way to cancel this operation. -This is often used to break down bigger tasks into smaller steps (a form of -cooperative multitasking). +This is often used to break down bigger tasks into smaller steps (a form +of cooperative multitasking). ```php $loop->futureTick(function () { diff --git a/examples/91-benchmark-ticks.php b/examples/91-benchmark-ticks.php index cdaa1e15..3f4690b3 100644 --- a/examples/91-benchmark-ticks.php +++ b/examples/91-benchmark-ticks.php @@ -9,7 +9,7 @@ $n = isset($argv[1]) ? (int)$argv[1] : 1000 * 100; for ($i = 0; $i < $n; ++$i) { - $loop->nextTick(function () { }); + $loop->futureTick(function () { }); } $loop->run(); diff --git a/examples/93-benchmark-ticks-delay.php b/examples/93-benchmark-ticks-delay.php index e242c65f..95ee78c6 100644 --- a/examples/93-benchmark-ticks-delay.php +++ b/examples/93-benchmark-ticks-delay.php @@ -11,7 +11,7 @@ if ($ticks > 0) { --$ticks; //$loop->addTimer(0, $tick); - $loop->nextTick($tick); + $loop->futureTick($tick); } else { echo 'done'; } diff --git a/examples/94-benchmark-timers-delay.php b/examples/94-benchmark-timers-delay.php index 69084e37..2d6cfa25 100644 --- a/examples/94-benchmark-timers-delay.php +++ b/examples/94-benchmark-timers-delay.php @@ -10,7 +10,7 @@ $tick = function () use (&$tick, &$ticks, $loop) { if ($ticks > 0) { --$ticks; - //$loop->nextTick($tick); + //$loop->futureTick($tick); $loop->addTimer(0, $tick); } else { echo 'done'; diff --git a/src/ExtEventLoop.php b/src/ExtEventLoop.php index d94e65db..538a3b9b 100644 --- a/src/ExtEventLoop.php +++ b/src/ExtEventLoop.php @@ -29,7 +29,7 @@ class ExtEventLoop implements LoopInterface public function __construct(EventBaseConfig $config = null) { $this->eventBase = new EventBase($config); - $this->futureTickQueue = new FutureTickQueue($this); + $this->futureTickQueue = new FutureTickQueue(); $this->timerEvents = new SplObjectStorage(); $this->createTimerCallback(); diff --git a/src/LibEvLoop.php b/src/LibEvLoop.php index 929d2eb6..f26ff6cd 100644 --- a/src/LibEvLoop.php +++ b/src/LibEvLoop.php @@ -26,7 +26,7 @@ class LibEvLoop implements LoopInterface public function __construct() { $this->loop = new EventLoop(); - $this->futureTickQueue = new FutureTickQueue($this); + $this->futureTickQueue = new FutureTickQueue(); $this->timerEvents = new SplObjectStorage(); } diff --git a/src/LibEventLoop.php b/src/LibEventLoop.php index b2c771cf..cf923d05 100644 --- a/src/LibEventLoop.php +++ b/src/LibEventLoop.php @@ -30,7 +30,7 @@ class LibEventLoop implements LoopInterface public function __construct() { $this->eventBase = event_base_new(); - $this->futureTickQueue = new FutureTickQueue($this); + $this->futureTickQueue = new FutureTickQueue(); $this->timerEvents = new SplObjectStorage(); $this->createTimerCallback(); diff --git a/src/LoopInterface.php b/src/LoopInterface.php index c2e5f75c..90ddba9d 100644 --- a/src/LoopInterface.php +++ b/src/LoopInterface.php @@ -91,14 +91,49 @@ public function isTimerActive(TimerInterface $timer); * This works very much similar to timers with an interval of zero seconds, * but does not require the overhead of scheduling a timer queue. * - * Unlike timers, callbacks are guaranteed to be executed in the order they - * are enqueued. + * The tick callback function MUST be able to accept zero parameters. + * + * The tick callback function MUST NOT throw an `Exception`. + * The return value of the tick callback function will be ignored and has + * no effect, so for performance reasons you're recommended to not return + * any excessive data structures. + * + * If you want to access any variables within your callback function, you + * can bind arbitrary data to a callback closure like this: + * + * ```php + * function hello(LoopInterface $loop, $name) + * { + * $loop->futureTick(function () use ($name) { + * echo "hello $name\n"; + * }); + * } + * + * hello('Tester'); + * ``` + * + * Unlike timers, tick callbacks are guaranteed to be executed in the order + * they are enqueued. * Also, once a callback is enqueued, there's no way to cancel this operation. * - * This is often used to break down bigger tasks into smaller steps (a form of - * cooperative multitasking). + * This is often used to break down bigger tasks into smaller steps (a form + * of cooperative multitasking). + * + * ```php + * $loop->futureTick(function () { + * echo 'b'; + * }); + * $loop->futureTick(function () { + * echo 'c'; + * }); + * echo 'a'; + * ``` + * + * See also [example #3](examples). * * @param callable $listener The callback to invoke. + * + * @return void */ public function futureTick(callable $listener); diff --git a/src/StreamSelectLoop.php b/src/StreamSelectLoop.php index 92fc5787..b4eafa2c 100644 --- a/src/StreamSelectLoop.php +++ b/src/StreamSelectLoop.php @@ -24,7 +24,7 @@ class StreamSelectLoop implements LoopInterface public function __construct() { - $this->futureTickQueue = new FutureTickQueue($this); + $this->futureTickQueue = new FutureTickQueue(); $this->timers = new Timers(); } diff --git a/src/Tick/FutureTickQueue.php b/src/Tick/FutureTickQueue.php index eeffd363..4a7c0bf7 100644 --- a/src/Tick/FutureTickQueue.php +++ b/src/Tick/FutureTickQueue.php @@ -2,20 +2,14 @@ namespace React\EventLoop\Tick; -use React\EventLoop\LoopInterface; use SplQueue; class FutureTickQueue { - private $eventLoop; private $queue; - /** - * @param LoopInterface $eventLoop The event loop passed as the first parameter to callbacks. - */ - public function __construct(LoopInterface $eventLoop) + public function __construct() { - $this->eventLoop = $eventLoop; $this->queue = new SplQueue(); } @@ -41,8 +35,7 @@ public function tick() while ($count--) { call_user_func( - $this->queue->dequeue(), - $this->eventLoop + $this->queue->dequeue() ); } } diff --git a/tests/AbstractLoopTest.php b/tests/AbstractLoopTest.php index 3351a8aa..2470e555 100644 --- a/tests/AbstractLoopTest.php +++ b/tests/AbstractLoopTest.php @@ -296,8 +296,7 @@ public function testFutureTick() { $called = false; - $callback = function ($loop) use (&$called) { - $this->assertSame($this->loop, $loop); + $callback = function () use (&$called) { $called = true; }; From 4827e00b5ac62a8d4d285f370bd8188eacbb0513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Wed, 26 Apr 2017 11:50:48 +0200 Subject: [PATCH 2/2] Mark internal tick API as final to discourage external usage --- src/Tick/FutureTickQueue.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Tick/FutureTickQueue.php b/src/Tick/FutureTickQueue.php index 4a7c0bf7..eb65345d 100644 --- a/src/Tick/FutureTickQueue.php +++ b/src/Tick/FutureTickQueue.php @@ -4,7 +4,15 @@ use SplQueue; -class FutureTickQueue +/** + * A tick queue implementation that can hold multiple callback functions + * + * This class should only be used internally, see LoopInterface instead. + * + * @see LoopInterface + * @internal + */ +final class FutureTickQueue { private $queue; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy