From efd037cd34f4d174d936b3ad764b0ba9d71c6416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Fri, 20 Apr 2018 22:21:59 +0200 Subject: [PATCH 1/2] Use sorted array to store timers and remove cancelled ones --- src/Timer/Timers.php | 68 +++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 45 deletions(-) diff --git a/src/Timer/Timers.php b/src/Timer/Timers.php index 17bbdac8..813072d4 100644 --- a/src/Timer/Timers.php +++ b/src/Timer/Timers.php @@ -3,8 +3,6 @@ namespace React\EventLoop\Timer; use React\EventLoop\TimerInterface; -use SplObjectStorage; -use SplPriorityQueue; /** * A scheduler implementation that can hold multiple timer instances @@ -17,14 +15,8 @@ final class Timers { private $time; - private $timers; - private $scheduler; - - public function __construct() - { - $this->timers = new SplObjectStorage(); - $this->scheduler = new SplPriorityQueue(); - } + private $timers = array(); + private $schedule = array(); public function updateTime() { @@ -38,36 +30,26 @@ public function getTime() public function add(TimerInterface $timer) { - $interval = $timer->getInterval(); - $scheduledAt = $interval + microtime(true); - - $this->timers->attach($timer, $scheduledAt); - $this->scheduler->insert($timer, -$scheduledAt); + $id = spl_object_hash($timer); + $this->timers[$id] = $timer; + $this->schedule[$id] = $timer->getInterval() + microtime(true); + asort($this->schedule); } public function contains(TimerInterface $timer) { - return $this->timers->contains($timer); + return isset($this->timers[spl_oject_hash($timer)]); } public function cancel(TimerInterface $timer) { - $this->timers->detach($timer); + $id = spl_object_hash($timer); + unset($this->timers[$id], $this->schedule[$id]); } public function getFirst() { - while ($this->scheduler->count()) { - $timer = $this->scheduler->top(); - - if ($this->timers->contains($timer)) { - return $this->timers[$timer]; - } - - $this->scheduler->extract(); - } - - return null; + return reset($this->schedule); } public function isEmpty() @@ -78,31 +60,27 @@ public function isEmpty() public function tick() { $time = $this->updateTime(); - $timers = $this->timers; - $scheduler = $this->scheduler; - - while (!$scheduler->isEmpty()) { - $timer = $scheduler->top(); - if (!isset($timers[$timer])) { - $scheduler->extract(); - $timers->detach($timer); - - continue; + foreach ($this->schedule as $id => $scheduled) { + // schedule is ordered, so loop until first timer that is not scheduled for execution now + if ($scheduled >= $time) { + break; } - if ($timers[$timer] >= $time) { - break; + // skip any timers that are removed while we process the current schedule + if (!isset($this->schedule[$id]) || $this->schedule[$id] !== $scheduled) { + continue; } - $scheduler->extract(); + $timer = $this->timers[$id]; call_user_func($timer->getCallback(), $timer); - if ($timer->isPeriodic() && isset($timers[$timer])) { - $timers[$timer] = $scheduledAt = $timer->getInterval() + $time; - $scheduler->insert($timer, -$scheduledAt); + // re-schedule if this is a periodic timer and it has not been cancelled explicitly already + if ($timer->isPeriodic() && isset($this->timers[$id])) { + $this->schedule[$id] = $timer->getInterval() + $time; + asort($this->schedule); } else { - $timers->detach($timer); + unset($this->timers[$id], $this->schedule[$id]); } } } From be70d8c65f9224ba1765e6761389bf593896114a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Sat, 21 Apr 2018 10:11:09 +0200 Subject: [PATCH 2/2] Improve performance by sorting timers only on demand --- src/Timer/Timers.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Timer/Timers.php b/src/Timer/Timers.php index 813072d4..7944b4c1 100644 --- a/src/Timer/Timers.php +++ b/src/Timer/Timers.php @@ -17,6 +17,7 @@ final class Timers private $time; private $timers = array(); private $schedule = array(); + private $sorted = true; public function updateTime() { @@ -33,7 +34,7 @@ public function add(TimerInterface $timer) $id = spl_object_hash($timer); $this->timers[$id] = $timer; $this->schedule[$id] = $timer->getInterval() + microtime(true); - asort($this->schedule); + $this->sorted = false; } public function contains(TimerInterface $timer) @@ -49,6 +50,12 @@ public function cancel(TimerInterface $timer) public function getFirst() { + // ensure timers are sorted to simply accessing next (first) one + if (!$this->sorted) { + $this->sorted = true; + asort($this->schedule); + } + return reset($this->schedule); } @@ -59,6 +66,12 @@ public function isEmpty() public function tick() { + // ensure timers are sorted so we can execute in order + if (!$this->sorted) { + $this->sorted = true; + asort($this->schedule); + } + $time = $this->updateTime(); foreach ($this->schedule as $id => $scheduled) { @@ -78,7 +91,7 @@ public function tick() // re-schedule if this is a periodic timer and it has not been cancelled explicitly already if ($timer->isPeriodic() && isset($this->timers[$id])) { $this->schedule[$id] = $timer->getInterval() + $time; - asort($this->schedule); + $this->sorted = false; } else { unset($this->timers[$id], $this->schedule[$id]); } 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