7、Workerman 基本使用 - Timer 定时器

作者: 温新

图书: 【Workerman 基本使用】

阅读: 170

时间: 2024-04-23 10:23:16

hi,我是温新,一名 PHPer

定时器有 add 定时执行某个函数,del 删除一个定时器。本篇定时器的案例来自文档,主要是为了动手操作。

add

作用:定时执行某个函数。原型如下:

int \Workerman\Timer::add(float $time_interval, callable $callback [,$args = array(), bool $persistent = true])

参数:

  • time_interval:定时器间隔时间,单位为秒,支持小数(可以精确到毫秒级别)
  • callback: 定时器触发时调用的回调函数
  • args:回调函数的参数数组,当定时器触发时,这些参数将传递给回调函数
  • persistent:是否持久化,如果为 true,则定时器会在进程重启后自动重新添加;为 false 则只执行一次

返回值:返回一个整数,代表计时器的 timerid。

定时器为匿名函数

<?php
/**
 * timer.php
 *
 * 定时器案例
 */

use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker();

// 开启多个进程时,需要注意业务是否有多进程并发问题
$worker->count = 1;

Timer::add(1, function (){
    echo time() . PHP_EOL;
});

Worker::runAll();

指定进程执行定时器

<?php
/**
 * timer.php
 *
 * 定时器案例
 */

use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker();

$worker->count = 4;

$worker->onWorkerStart = function (Worker $worker) {
    // 编号为 2 的进程中执行定时器
    if ($worker->id == 2) {
        Timer::add(1, function () use ($worker) {
            echo $worker->id . '==' . time() . PHP_EOL;
        });
    }
};

Worker::runAll();

定时器,闭包传递参数

<?php
/**
 * timer.php
 *
 * 定时器案例
 */

use Workerman\Connection\TcpConnection;
use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('tcp://0.0.0.0:8888');

$worker->count = 4;

$worker->onConnect = function (TcpConnection $connection) {
    // 获取当前连接建立的时间并
    $connectTime = date('Y-m-d H:i:s') . PHP_EOL;
    // timer_id 保存为动态属性
    // 使用闭包传递参数
    $connection->timer_id = Timer::add(1, function($connectTime) use ($connection, $connectTime) {
        $connection->send($connectTime);
    });
};

$worker->onClose = function (TcpConnection $connection) {
    // 删除定时器
    Timer::del($connection->timer_id);
};

Worker::runAll();

执行一下看看情况

$ telnet 127.0.0.1 8888
# 思考下,时间为什么是一样的?
2024-02-29 07:30:12
2024-02-29 07:30:12

定时器,使用接口参数传递参数

<?php
/**
 * timer.php
 *
 * 定时器案例
 */

use Workerman\Connection\TcpConnection;
use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('tcp://0.0.0.0:8888');

$worker->count = 4;

$worker->onConnect = function (TcpConnection $connection) {
    $connectTime = date('Y-m-d H:i:s') . PHP_EOL;
 
    $connection->timer_id = Timer::add(1, function ($connection, $connectTIme) {
        $connection->send($connectTIme);
    }, [$connection, $connectTime]);
};

$worker->onClose = function (TcpConnection $connection) {
    // 删除定时器
    Timer::del($connection->timer_id);
};

Worker::runAll();

定时器为普通函数

<?php
/**
 * timer.php
 *
 * 定时器案例
 */

use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker();

$worker->count = 1;

$worker->onWorkerStart = function (Worker $worker) {
    $connectTime = date('Y-m-d H:i:s') . PHP_EOL;
    // 定时器只执行一次
    Timer::add(1, 'get_date', [$connectTime], false);
};

function get_date($connectTime) {
    echo $connectTime;
};

Worker::runAll();

定时器为类的方法

<?php
/**
 * timer.php
 *
 * 定时器案例,定时器方法为类的方法
 */

use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

class Person {
    public function getName(string $name) {
        echo $name . PHP_EOL;
    }
}


$worker = new Worker();

$worker->count = 1;

$worker->onWorkerStart = function (Worker $worker) {
    $person = new Person();
    $name   = '王美丽';
    Timer::add(1, [$person, 'getName'], [$name]);
};

function get_date($connectTime) {
    echo $connectTime;
};

Worker::runAll();

类中的方法使用定时器

<?php
/**
 * timer.php
 *
 * 定时器案例,定时器方法为类的方法
 */

use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

class Person {
    public function getName(string $name):void {
        echo $name . PHP_EOL;
    }
    
    // 类的方法中使用定时器
    public function handleTimer(string $name): void
    {
        Timer::add(1, [$this, 'getName'], [$name]);
    }
}

$worker = new Worker();

$worker->onWorkerStart = function (Worker $worker) {
    $person = new Person();
    $name   = '王美丽丽';

    $person->handleTimer($name);
};

Worker::runAll();

定时器为类的静态方法

<?php
/**
 * timer.php
 *
 * 定时器案例,定时器为类的静态方法
 */

use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

class Person {
    public static function getName(string $name):void {
        echo $name . PHP_EOL;
    }

}

$worker = new Worker();

$worker->onWorkerStart = function () {
    $name = '王小丽';

    // 定时调用类的静态方法
    Timer::add(1, [Person::class, 'getName'], [$name]);
};

Worker::runAll();

定时器为带有命名空间的类的静态方法

<?php
/**
 * timer.php
 *
 * 定时器案例,定时器为类的静态方法
 */
namespace Task;

use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

class Person {
    public static function getName(string $name):void {
        echo $name . PHP_EOL;
    }

}

$worker = new Worker();

$worker->onWorkerStart = function () {
    $name = '王小丽';

    // 定时调用带命名空间的类的静态方法
    Timer::add(1, [\Task\Person::class, 'getName'], [$name]);
};

Worker::runAll();

删除定时器

<?php
/**
 * timer.php
 *
 * 定时器案例,删除定时器
 */

use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';


$worker = new Worker();

$worker->onWorkerStart = function () {
    $count = 1;

    // 要把 $timerId 传递到函数内容,必须使用 &
    $timerId = Timer::add(1, function () use (&$timerId, &$count) {
        echo $count . PHP_EOL;
        if ($count++ >= 3) {
            echo '删除定时器 ' . $timerId . PHP_EOL;
            Timer::del($timerId);
        }
    });
};

Worker::runAll();

传递参数的方式删除定时器

<?php
/**
 * timer.php
 *
 * 定时器案例,删除定时器
 */

use Workerman\Worker;
use Workerman\Timer;

require_once __DIR__ . '/vendor/autoload.php';

class Person
{
    public function send(int $timerId):void
    {
        // 临时给当前对象添加一个count属性,记录定时器运行次数
        $this->count = empty($this->count) ? 1 : $this->count;
        echo $this->count . PHP_EOL;
        if ($this->count++ >= 3) {
            echo '定时器已删除' . PHP_EOL;
            Timer::del($timerId);
        }
    }
}

$worker = new Worker();

$worker->onWorkerStart = function () {
    $person = new Person();

    $timerId = Timer::add(1, [$person, 'send'], [&$timerId]);
};

Worker::runAll();

关于定时器的注意事项请阅读文档,这里只摘抄一点:

  • 只能在onXXXX回调中添加定时器。全局的定时器推荐在onWorkerStart回调中设置,针对某个连接的定时器推荐在onConnect中设置

crontab 定时器

workerman/crontab 是一个基于workerman的定时任务程序,类似linux的crontab。workerman/crontab支持秒级别定时。

使用 workerman/crontab需要先设置好php的时区,否则运行结果可能和预期的不一致。

时间说明

0   1   2   3   4   5
|   |   |   |   |   |
|   |   |   |   |   +------ day of week (0 - 6) (Sunday=0)
|   |   |   |   +------ month (1 - 12)
|   |   |   +-------- day of month (1 - 31)
|   |   +---------- hour (0 - 23)
|   +------------ min (0 - 59)
+-------------- sec (0-59)[可省略,如果没有0位,则最小时间粒度是分钟]

安装

$ composer require workerman/crontab --ignore-platform-req=ext-pthreads

crontab 使用

<?php
/**
 * timer.php
 *
 * 定时器案例,每秒执行
 */

use Workerman\Worker;
use Workerman\Crontab\Crontab;

require_once __DIR__ . '/vendor/autoload.php';

date_default_timezone_set('PRC');

$worker = new Worker();

$worker->onWorkerStart	 = function () {
    // 每秒执行一次
    new Crontab('* * * * * *', function () {
        echo date('Y-m-d H:i:s')."\n";
    });
};

Worker::runAll();
请登录后再评论