使用Swoole实现毫秒级定时器

  使用Swoole\Timer::tick()方法实现毫秒级定时器

<?php
set_time_limit(0); // 不限制脚本最大执行时间
date_default_timezone_set('PRC');

$name = '张三';
$age = 18;

// 每1000毫秒执行一次,其中{$timer_id}为定时器ID
Swoole\Timer::tick(1000, static function ($timer_id) use ($name, &$age) {
    $datetime = date('Y-m-d H:i:s');
    echo "[$datetime 触发定时器(\$timer_id={$timer_id})] 俺叫{$name},俺今年{$age}岁。" . PHP_EOL;

    $age++;
    if ($age > 25) {
        $result = Swoole\Timer::clear($timer_id); // 清除定时器
        if ($result === true) {
            echo "清除定时器(\$timer_id=$timer_id)成功" . PHP_EOL;
        } else {
            echo "清除定时器(\$timer_id=$timer_id)失败" . PHP_EOL;
        }
    }
});

Swoole\Event::wait();

//========== 总结 ==========//
// 1、PHP脚本文件必须以CLI模式执行,命令和输出结果如下:
//    [root@localhost ~]# /program/php/bin/php /inetpub/wwwroot/manong/tick.php
//    [yyyy-mm-dd hh:ii:00 触发定时器($timer_id=1)] 俺叫张三,俺今年18岁。
//    [yyyy-mm-dd hh:ii:01 触发定时器($timer_id=1)] 俺叫张三,俺今年19岁。
//    [yyyy-mm-dd hh:ii:02 触发定时器($timer_id=1)] 俺叫张三,俺今年20岁。
//    [yyyy-mm-dd hh:ii:03 触发定时器($timer_id=1)] 俺叫张三,俺今年21岁。
//    [yyyy-mm-dd hh:ii:04 触发定时器($timer_id=1)] 俺叫张三,俺今年22岁。
//    [yyyy-mm-dd hh:ii:05 触发定时器($timer_id=1)] 俺叫张三,俺今年23岁。
//    [yyyy-mm-dd hh:ii:06 触发定时器($timer_id=1)] 俺叫张三,俺今年24岁。
//    [yyyy-mm-dd hh:ii:07 触发定时器($timer_id=1)] 俺叫张三,俺今年25岁。
//    清除定时器($timer_id=1)成功
//    [root@localhost ~]#



  使用Swoole\Timer::after()方法实现毫秒级定时器

<?php
set_time_limit(0); // 不限制脚本最大执行时间
date_default_timezone_set('PRC');


function task(string $name, int $age): void
{
    // 在1000毫秒后执行函数(只执行一次,所以要结合递归实现定时调用)
    Swoole\Timer::after(1000, static function () use ($name, &$age) {
        $datetime = date('Y-m-d H:i:s');
        echo "[$datetime] 俺叫{$name},俺今年{$age}岁。" . PHP_EOL;

        $age++;
        if ($age <= 25) {
            task($name, $age); // 递归
        }
    });
}

task('张三', 18);

Swoole\Event::wait();

//========== 总结 ==========//
// 1、PHP脚本文件必须以CLI模式执行,命令和输出结果如下:
//    [root@localhost ~]# /program/php/bin/php /inetpub/wwwroot/manong/after.php
//    [yyyy-mm-dd hh:ii:00 触发定时器($timer_id=1)] 俺叫张三,俺今年18岁。
//    [yyyy-mm-dd hh:ii:01 触发定时器($timer_id=1)] 俺叫张三,俺今年19岁。
//    [yyyy-mm-dd hh:ii:02 触发定时器($timer_id=1)] 俺叫张三,俺今年20岁。
//    [yyyy-mm-dd hh:ii:03 触发定时器($timer_id=1)] 俺叫张三,俺今年21岁。
//    [yyyy-mm-dd hh:ii:04 触发定时器($timer_id=1)] 俺叫张三,俺今年22岁。
//    [yyyy-mm-dd hh:ii:05 触发定时器($timer_id=1)] 俺叫张三,俺今年23岁。
//    [yyyy-mm-dd hh:ii:06 触发定时器($timer_id=1)] 俺叫张三,俺今年24岁。
//    [yyyy-mm-dd hh:ii:07 触发定时器($timer_id=1)] 俺叫张三,俺今年25岁。
//    [root@localhost ~]#



  每日定时任务的实现

<?php
set_time_limit(0); // 不限制脚本最大执行时间
date_default_timezone_set('PRC');

function task(int $taskTime): void
{
    $nowTime = time();

    // 已经过了当天任务执行时间,将任务执行时间设为次日
    if ($nowTime > $taskTime) {
        $taskTime += 86400;
    }

    $diff = $taskTime - $nowTime;
    if ($diff > 0) {
        // 创建任务,其中$id为任务ID,从1开始递增
        $id = Swoole\Timer::after($diff * 1000, static function () use ($taskTime) {
            echo '开始执行任务' . PHP_EOL;

            // 模拟执行任务(长耗时操作)
            echo '执行任务中';
            for ($i = 0; $i < 10; $i++) {
                echo '.';
                sleep(1);
            }
            echo PHP_EOL;

            echo '任务执行完毕' . PHP_EOL;

            task($taskTime + 86400); // 创建下一次任务
        });

        if (is_int($id) && $id > 0) {
            echo "创建任务[id=$id]成功,执行时间[" . date('Y-m-d H:i:s', $taskTime) . "],距离执行时间还有[{$diff}秒]" . PHP_EOL;
        } else {
            echo '创建任务失败';
        }
    }
}

// 执行当天任务
task(strtotime('today 03:45:00'));

Swoole\Event::wait();

//========== 总结 ==========//
// 1、实现每天凌晨三点四十五分(03:45)执行任务的思路:
//    算出当前时间距离03:45还有多久,假设时间差为T毫秒,那么就可以使用Swoole\Timer::after(T)实现在03:45执行任务,
//    到点执行完任务后再计算距离下一个03:45还有多久,继续使用Swoole\Timer::after()实现到点执行任务,如此不断循环,
//    就能实现每天凌晨三点四十五分(03:45)执行一次任务。

Copyright © 2024 码农人生. All Rights Reserved