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

作者: 温新

分类: 【高性能PHP】

阅读: 2944

时间: 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

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">Swoole\Timer</span>::<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">tick</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1000</span>, <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span>(){</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">echo</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">"hello swoole\n"</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">});</span>

执行结果

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">php timer.php </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">hello swoole</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">hello swoole</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">hello swoole</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">hello swoole</span>

Laravel-S实现定时任务

步骤一:创建一个定时任务类并继承CronJob

位置:app/Jobs/Timer/DemoCronJob.php

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">  </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">namespace</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">App\Jobs\Timer</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">use</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">Hhxsv5\LaravelS\Swoole\Timer\CronJob</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">use</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">Illuminate\Support\Facades\Log</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">class</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">TestCronJob</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">extends</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">CronJob</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">{</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">protected</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$i</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">0</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 每隔 1000ms 执行一次任务</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">public</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">interval</span>()</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">return</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1000</span>;   <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 定时器间隔,单位为 ms</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    }</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 是否在设置之后立即触发 run 方法执行</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">public</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">isImmediate</span>()</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 是否立即执行第一次,false则等待间隔时间后执行第一次</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">return</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">false</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    }</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 该方法可类比为 Swoole 定时器中的回调方法</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">public</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">run</span>()</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">Log</span>::<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">info</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">__METHOD__</span>, [<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'start'</span>, <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$this</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">i</span>, <span style="box-sizing: border-box;color: rgb(232, 191, 106) !important">microtime</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">true</span>)]);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$this</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">i</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">++</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">Log</span>::<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">info</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">__METHOD__</span>, [<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'end'</span>, <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$this</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">i</span>, <span style="box-sizing: border-box;color: rgb(232, 191, 106) !important">microtime</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">true</span>)]);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">if</span> (<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$this</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">i</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">==</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">10</span>) { <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 总共运行3次</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">            <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">Log</span>::<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">info</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">__METHOD__</span>, [<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'stop'</span>, <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$this</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">i</span>, <span style="box-sizing: border-box;color: rgb(232, 191, 106) !important">microtime</span>(<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">true</span>)]);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">            <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 终止此定时任务,但restart/reload后会再次运行</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">            <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$this</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">stop</span>();</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        }</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    }</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">}</span>

步骤二:注册定时任务

位置:/config/laravels.php

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'timer'</span>  <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=></span> [</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'enable'</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=></span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">true</span>,</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'jobs'</span>   <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=></span> [</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">        <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">\App\Jobs\Timer\DemoCronJob</span>::<span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">class</span>, </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    ],</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">    <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'max_wait_time'</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=></span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">5</span>, <span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// Max waiting time of reloading</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">],</span>

步骤三:启动laravel-s

位置:项目根目录下

<span style="color: rgb(255, 255, 255);">php bin/laravels start</span><br></br>

步骤四:查看laravel.log日志

位置:storage/logs/laravel.php

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">[<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">2021</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">03</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">11</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">16</span>:<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">28</span>:<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">43</span>] <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">local</span>.<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">INFO</span>: <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">App\Jobs\Timer\DemoCronJob</span>::<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">run</span> [<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">"end"</span>,<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1</span>,<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1615480123.445053</span>] </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">[<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">2021</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">03</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">11</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">16</span>:<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">28</span>:<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">44</span>] <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">local</span>.<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">INFO</span>: <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">App\Jobs\Timer\DemoCronJob</span>::<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">run</span> [<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">"start"</span>,<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1</span>,<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1615480124.442784</span>] </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 省略...</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">[<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">2021</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">03</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">11</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">16</span>:<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">28</span>:<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">53</span>] <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">local</span>.<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">INFO</span>: <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">App\Jobs\Timer\DemoCronJob</span>::<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">run</span> [<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">"end"</span>,<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">11</span>,<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1615480133.444201</span>] </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">[<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">2021</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">03</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">11</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">16</span>:<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">28</span>:<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">53</span>] <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">local</span>.<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">INFO</span>: <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">App\Jobs\Timer\DemoCronJob</span>::<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">run</span> [<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">"stop"</span>,<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">11</span>,<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">1615480133.444308</span>]</span>

(完)

请登录后再评论