|PHPer都应该知道的Swoole知识-定时器

|PHPer都应该知道的Swoole知识-定时器

文章图片

|PHPer都应该知道的Swoole知识-定时器

文章图片

|PHPer都应该知道的Swoole知识-定时器

本节将讲述如下三个问题:
PHP本身的定时器介绍
Swoole中定时器的使用方法
Swoole定时器的底层原理

01PHP本身的定时器介绍
先说说原生PHP如何实现定时器 , PHP的定时器是通过 pcntl_alarm 实现的:pcntl_alarm ( int $seconds ) :int
pcntl_alarm 函数的作用是为进程设置一个alarm闹钟信号 。 调用这个方法后会创建一个计数器 , 在指定的秒数后向进程发送一个SIGALRM信号 。 每次对 pcntl_alarm 的调用都会取消之前设置的alarm信号 。
其中 , $seconds 为等待的秒数 , 如果 $seconds 设置为0 , 将不会创建alarm信号 。 调用这个函数后返回上次alarm调度剩余的秒数 , 或者之前没有alarm调度时返回0 。
下面我们看一个例子 , pcntl_signal() 函数安装信号处理器 , pcntl_signal_dispatch() 调用等待信号的处理器 。

pcntl_alarm() 函数是基于时钟信号 + tick函数实现的 , 存在一些缺陷:
最大进支持到秒 , 而Swoole Timer可以到毫秒级别
不支持同时设定多个定时器程序
pcntl_alarm() 依赖 declare(ticks = 1) , 性能很差
02Swoole中定时器的使用方法
Swoole中的定时器可以达到毫秒精度 , 同时可以支持添加大量定时器 。在Swoole中可以使用 Timer::tick 来设置一个间隔时钟定时器 , 调用Timer::clear来清除定时器 。 函数定义如下:
【|PHPer都应该知道的Swoole知识-定时器】int Swoole\\Timer::tick(int $msec callable $callback ……$params);
这个函数的别名是 swoole_timer_tick() 。 $msec 为指定的时间 , 单位是毫秒 。 $callback 为时间到期后执行的函数 。 $callback 回调函数会接收多个参数 , 第一个是定时器的ID 。 注意:定时器仅在当前进程空间内有效 。 定时器是纯异步实现的 , 不能与阻塞IO的函数一起使用 , 否则定时器的执行时间会发生错乱 。
下面是定时器在 websocket 的 onMessage 回调函数中的一个 demo ,

触发 onMessage 回调后在客户端打印出如下信息 , 截图

除此之外swoole还提供了另外一个函数 Timer::after 来实现定时器 , 这个函数是的作用是在指定时间后执行回调函数 。 函数原型如下:
int Swoole\\Timer::after(int $after_time_ms callable $callback_function ……$params);
这个函数的别名是 swoole_timer_after 。 Timer::after是一个一次性定时器 , 执行完成后就会销毁 。 示例代码如下:

除了设置定时器的函数外 , Swoole还提供了另外几个函数:
function Timer::set(array $array); //设置定时器的参数
Timer\\Iterator Timer::list();//返回定时器迭代器 可使用foreach遍历全局所有timer的id
array Timer::info(int $id);//返回timer的信息
bool Swoole\\Timer::clear(int $timer_id);//使用定时器ID来删除定时器
bool Timer::clearAll();//清除当前工作进程内的所有定时器
03Swoole定时器的底层原理
Swoole定时器底层是基于epoll_wait 和 setitimer 实现 , 数据结构使用的是最小堆 。
Swoole定时器回调函数的执行时间不影响下一次定时器执行的时间 。 如果定时器回调函数的执行时间过长 , 甚至覆盖了下一次定时器执行的时间 。 底层会进行时间校正 , 丢弃已过期的行为 , 在下一时间回调 。


    推荐阅读