8000 Merge pull request #164 from clue-labs/timers · reactphp/event-loop@b12a79a · GitHub
[go: up one dir, main page]

Skip to content

Commit b12a79a

Browse files
authored
Merge pull request #164 from clue-labs/timers
StreamSelectLoop: Improve memory consumption and runtime performance for timers
2 parents e1e0647 + be70d8c commit b12a79a

File tree

1 file changed

+34
-43
lines changed

1 file changed

+34
-43
lines changed

src/Timer/Timers.php

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
namespace React\EventLoop\Timer;
44

55
use React\EventLoop\TimerInterface;
6-
use SplObjectStorage;
7-
use SplPriorityQueue;
86

97
/**
108
* A scheduler implementation that can hold multiple timer instances
@@ -17,14 +15,9 @@
1715
final class Timers
1816
{
1917
private $time;
20-
private $timers;
21-
private $scheduler;
22-
23-
public function __construct()
24-
{
25-
$this->timers = new SplObjectStorage();
26-
$this->scheduler = new SplPriorityQueue();
27-
}
18+
private $timers = array();
19+
private $schedule = array();
20+
private $sorted = true;
2821

2922
public function updateTime()
3023
{
@@ -38,36 +31,32 @@ public function getTime()
3831

3932
public function add(TimerInterface $timer)
4033
{
41-
$interval = $timer->getInterval();
42-
$scheduledAt = $interval + microtime(true);
43-
44-
$this->timers->attach($timer, $scheduledAt);
45-
$this->scheduler->insert($timer, -$scheduledAt);
34+
$id = spl_object_hash($timer);
35+
$this->timers[$id] = $timer;
36+
$this->schedule[$id] = $timer->getInterval() + microtime(true);
37+
$this->sorted = false;
4638
}
4739

4840
public function contains(TimerInterface $timer)
4941
{
50-
return $this->timers->contains($timer);
42+
return isset($this->timers[spl_oject_hash($timer)]);
5143
}
5244

5345
public function cancel(TimerInterface $timer)
5446
{
55-
$this->timers->detach($timer);
47+
$id = spl_object_hash($timer);
48+
unset($this->timers[$id], $this->schedule[$id]);
5649
}
5750

5851
public function getFirst()
5952
{
60-
while ($this->scheduler->count()) {
61-
$timer = $this->scheduler->top();
62-
63-
if ($this->timers->contains($timer)) {
64-
return $this->timers[$timer];
65-
}
66-
67-
$this->scheduler->extract();
53+
// ensure timers are sorted to simply accessing next (first) one
54+
if (!$this->sorted) {
55+
$this->sorted = true;
56+
asort($this->schedule);
6857
}
6958

70-
return null;
59+
return reset($this->schedule);
7160
}
7261

7362
public function isEmpty()
@@ -77,32 +66,34 @@ public function isEmpty()
7766

7867
public function tick()
7968
{
80-
$time = $this->updateTime();
81-
$timers = $this->timers;
82-
$scheduler = $this->scheduler;
83-
84-
while (!$scheduler->isEmpty()) {
85-
$timer = $scheduler->top();
69+
// ensure timers are sorted so we can execute in order
70+
if (!$this->sorted) {
71+
$this->sorted = true;
72+
asort($this->schedule);
73+
}
8674

87-
if (!isset($timers[$timer])) {
88-
$scheduler->extract();
89-
$timers->detach($timer);
75+
$time = $this->updateTime();
9076

91-
continue;
77+
foreach ($this->schedule as $id => $scheduled) {
78+
// schedule is ordered, so loop until first timer that is not scheduled for execution now
79+
if ($scheduled >= $time) {
80+
break;
9281
}
9382

94-
if ($timers[$timer] >= $time) {
95-
break;
83+
// skip any timers that are removed while we process the current schedule
84+
if (!isset($this->schedule[$id]) || $this->schedule[$id] !== $scheduled) {
85+
continue;
9686
}
9787

98-
$scheduler->extract();
88+
$timer = $this->timers[$id];
9989
call_user_func($timer->getCallback(), $timer);
10090

101-
if ($timer->isPeriodic() && isset($timers[$timer])) {
102-
$timers[$timer] = $scheduledAt = $timer->getInterval() + $time;
103-
$scheduler->insert($timer, -$scheduledAt);
91+
// re-schedule if this is a periodic timer and it has not been cancelled explicitly already
92+
if ($timer->isPeriodic() && isset($this->timers[$id])) {
93+
$this->schedule[$id] = $timer->getInterval() + $time;
94+
$this->sorted = false;
10495
} else {
105-
$timers->detach($timer);
96+
unset($this->timers[$id], $this->schedule[$id]);
10697
}
10798
}
10899
}

0 commit comments

Comments
 (0)
0