基于Laravel-S集成Swoole实现毫秒级定时任务
Swoole定时器Timer
毫秒精度的定时器。底层基于 epoll_wait
和 setitimer
实现,数据结构使用最小堆
,可支持添加大量定时器。
- 在同步 IO 进程中使用
setitimer
和信号实现,如Manager
和TaskWorker
进程 - 在异步 IO 进程中使用
epoll_wait
/kevent
/poll
/select
超时时间实现
性能
底层使用最小堆数据结构实现定时器,定时器的添加和删除,全部为内存操作,因此性能是非常高的。
差异
Timer
与 PHP
本身的 pcntl_alarm
是不同的。pcntl_alarm
是基于时钟信号 + tick
函数实现存在一些缺陷:
- 最大仅支持到秒,而
Timer
可以到毫秒级别 - 不支持同时设定多个定时器程序
-
pcntl_alarm
依赖declare(ticks = 1)
,性能很差
简单案例第秒执行一次
位置:/www/timer.php
Swoole\Timer::tick(1000, function(){
echo "hello swoole\n";
});
执行结果
php timer.php
hello swoole
hello swoole
hello swoole
hello swoole
Laravel-S实现定时任务
步骤一:创建一个定时任务类并继承CronJob
位置:app/Jobs/Timer/DemoCronJob.php
<?php
namespace App\Jobs\Timer;
use Hhxsv5\LaravelS\Swoole\Timer\CronJob;
use Illuminate\Support\Facades\Log;
class TestCronJob extends CronJob
{
protected $i = 0;
// 每隔 1000ms 执行一次任务
public function interval()
{
return 1000; // 定时器间隔,单位为 ms
}
// 是否在设置之后立即触发 run 方法执行
public function isImmediate()
{
// 是否立即执行第一次,false则等待间隔时间后执行第一次
return false;
}
// 该方法可类比为 Swoole 定时器中的回调方法
public function run()
{
Log::info(__METHOD__, ['start', $this->i, microtime(true)]);
$this->i++;
Log::info(__METHOD__, ['end', $this->i, microtime(true)]);
if ($this->i == 10) { // 总共运行3次
Log::info(__METHOD__, ['stop', $this->i, microtime(true)]);
// 终止此定时任务,但restart/reload后会再次运行
$this->stop();
}
}
}
步骤二:注册定时任务
位置:/config/laravels.php
'timer' => [
'enable' => true,
'jobs' => [
\App\Jobs\Timer\DemoCronJob::class,
],
'max_wait_time' => 5, // Max waiting time of reloading
],
步骤三:启动laravel-s
位置:项目根目录下
php bin/laravels start^C
步骤四:查看laravel.log日志
位置:storage/logs/laravel.php
[2021-03-11 16:28:43] local.INFO: App\Jobs\Timer\DemoCronJob::run ["end",1,1615480123.445053]
[2021-03-11 16:28:44] local.INFO: App\Jobs\Timer\DemoCronJob::run ["start",1,1615480124.442784]
// 省略...
[2021-03-11 16:28:53] local.INFO: App\Jobs\Timer\DemoCronJob::run ["end",11,1615480133.444201]
[2021-03-11 16:28:53] local.INFO: App\Jobs\Timer\DemoCronJob::run ["stop",11,1615480133.444308]
2021-03-12
请登录后再评论