核心:秒级定时器 - lizhibin205/php_crond GitHub Wiki
秒级定时器
秒级定时器是通过包react/event-loop实现的
$loop = \React\EventLoop\Factory::create();
$loop->addPeriodicTimer(1, function($timer) use ($loop) {
//your code
});
$loop->run();
event-loop实现方式
namespace React\EventLoop;
/**
* The `Factory` class exists as a convenient way to pick the best available event loop implementation.
*/
final class Factory
{
/**
* Creates a new event loop instance
*
* ```php
* $loop = React\EventLoop\Factory::create();
* ```
*
* This method always returns an instance implementing `LoopInterface`,
* the actual event loop implementation is an implementation detail.
*
* This method should usually only be called once at the beginning of the program.
*
* @return LoopInterface
*/
public static function create()
{
// @codeCoverageIgnoreStart
if (\function_exists('uv_loop_new')) {
// only use ext-uv on PHP 7
return new ExtUvLoop();
} elseif (\class_exists('libev\EventLoop', false)) {
return new ExtLibevLoop();
} elseif (\class_exists('EvLoop', false)) {
return new ExtEvLoop();
} elseif (\class_exists('EventBase', false)) {
return new ExtEventLoop();
} elseif (\function_exists('event_base_new') && \PHP_MAJOR_VERSION === 5) {
// only use ext-libevent on PHP 5 for now
return new ExtLibeventLoop();
}
return new StreamSelectLoop();
// @codeCoverageIgnoreEnd
}
}
StreamSelectLoop如何工作
1. 添加周期事件
$loop->addPeriodicTimer(1, function($timer) use ($loop) {
//wort code
});
addPeriodicTimer方法将会生成一个React\EventLoop\Timer\Timer对象,并使用React\EventLoop\Timer\Timers进行管理。 Timer将会存储于SplObjectStorage中,$storage[$timer] = [下次执行时间],并且插入优先级队列SplPriorityQueue(该队列优先级为- ([事件间隔] + [当前时间]))。因此,队列第一个元素就是下个次执行的事件Timer。
2. 执行run方法
在run方法中,React\EventLoop\Timer\Timers对象会执行tick()方法,该方法会从SplPriorityQueue中不断取出Timer,并执行Timer的callback,直到队列为空,如果Timer是周期性事件,则重新放到SplPriorityQueue队列。
3. usleep
计算方式:SplPriorityQueue队列第一个元素未来执行时间 - 当前时间。比如档期时间是1539582930,3个Timer分别是3,4,5,则sleep时间就是3秒。
警告:由于这种方式是单进程处理,不要在Timer的callback执行阻塞操作。否则会导致某个周期的Timer无法执行。