基于Laravel-S集成Swoole实现毫秒级定时任务

作者: 温新

分类: 【高性能PHP】

阅读: 3343

时间: 2021-03-11 16:36:05

Swoole定时器Timer

毫秒精度的定时器。底层基于 epoll_waitsetitimer 实现,数据结构使用最小堆,可支持添加大量定时器。

  • 在同步 IO 进程中使用 setitimer 和信号实现,如 ManagerTaskWorker 进程
  • 在异步 IO 进程中使用 epoll_wait/kevent/poll/select 超时时间实现

性能

底层使用最小堆数据结构实现定时器,定时器的添加和删除,全部为内存操作,因此性能是非常高的。

差异

TimerPHP 本身的 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

请登录后再评论