博客
关于我
php如何使用Swoole实现毫秒级定时任务
阅读量:105 次
发布时间:2019-02-26

本文共 5362 字,大约阅读时间需要 17 分钟。

项目开发中,如果有定时任务的业务需求,可以选择使用Linux的crontab工具来处理。但需要注意的是,crontab的最小粒度是分钟级别,对于需要秒级或毫秒级定时任务来说,它就不足以满足需求。幸运的是,Swoole提供了强大的毫秒定时器功能,可以更灵活地满足各种定时任务的需求。

应用场景举例

在实际项目中,我们可能会遇到以下几种定时任务的场景:

  • 场景一:每隔30秒获取一次本机内存使用率

    这种场景常见于系统性能监控中。虽然实时性要求较高,但又能控制好执行频率,适合后台服务器性能监控,可以生成可视化图表。可以是30秒获取一次内存使用率,也可以是10秒,具体取决于业务需求。

  • 场景二:2分钟后执行报表发送任务

    如果需要在特定时间执行一次性任务,crontab虽然可以实现,但比较繁琐。使用Swoole的定时器可以直接定义执行时间,实现更简便。

  • 场景三:每天凌晨2点钟定时请求第三方接口

    这种场景需要考虑接口响应情况。可以设置定时器在5分钟后重试,直到成功或达到最大尝试次数后停止。

  • Swoole毫秒定时器

    Swoole提供了多种异步毫秒定时器函数,支持以毫秒级精度执行定时任务:

    • swoole_timer_tick(int $msec, callable $callback)

      设置一个间隔$msec$毫秒的定时器,每隔$msec$毫秒执行一次$callback$,类似于JavaScript的setInterval()

    • swoole_timer_after(int $after_time_ms, mixed $callback_function)

      在指定的时间$after_time_ms$后执行$callback_function$,类似于JavaScript的setTimeout()

    • swoole_timer_clear(int $timer_id)

      删除指定id的定时器,类似于JavaScript的clearInterval()

    解决方案

    场景一

    可以使用Swoole_Timer_Tick每30秒执行一次,获取本机内存使用率,并将结果存储或发送到指定位置。示例代码如下:

    swoole_timer_tick(30000, function($timer) use ($task_id) {
    $memPercent = $this->getMemoryUsage();
    echo date('Y-m-d H:i:s') . '当前内存使用率:' . $memPercent . "\n";
    });

    场景二

    使用Swoole_Timer_After在2分钟后执行特定任务。示例代码如下:

    swoole_timer_after(120000, function() use ($str) {
    $this->sendReport();
    echo "send report, $str\n";
    });

    场景三

    可以通过Swoole_Timer_Tick每5分钟执行一次,尝试请求第三方接口。示例代码如下:

    swoole_timer_tick(5 * 60 * 1000, function($timer) use ($url) {
    $rs = $this->postUrl($url);
    if ($rs) {
    // 业务代码...
    swoole_timer_clear($timer); // 停止定时器
    echo date('Y-m-d H:i:s') . "请求接口任务执行成功\n";
    } else {
    echo date('Y-m-d H:i:s') . "请求接口失败,5分钟后再次尝试\n";
    }
    });

    示例代码

    文件:src/App/Task.php

    namespace Helloweba\Swoole;
    use swoole_server;
    class Task {
    protected $serv;
    protected $host = '127.0.0.1';
    protected $port = 9506;
    protected $taskName = 'swooleTask';
    protected $pidPath = '/run/swooletask.pid';
    protected $options = [
    'worker_num' => 4,
    'daemonize' => true,
    'log_file' => '/data/log/swoole-task.log',
    'log_level' => 0,
    'dispatch_mode' => 1,
    'task_worker_num' => 4,
    'task_ipc_mode' => 3,
    ];
    public function __construct($options = []) {
    date_default_timezone_set('PRC');
    $this->serv = new swoole_server($this->host, $this->port);
    if (!empty($options)) {
    $this->options = array_merge($this->options, $options);
    }
    $this->serv->set($this->options);
    $this->serv->on('Start', [$this, 'onStart']);
    $this->serv->on('Connect', [$this, 'onConnect']);
    $this->serv->on('Receive', [$this, 'onReceive']);
    $this->serv->on('Task', [$this, 'onTask']);
    $this->serv->on('Finish', [$this, 'onFinish']);
    $this->serv->on('Close', [$this, 'onClose']);
    }
    public function start() {
    $this->serv->start();
    }
    public function onStart($serv) {
    cli_set_process_title($this->taskName);
    $pid = "{$serv->master_pid}\n{$serv->manager_pid}";
    file_put_contents($this->pidPath, $pid);
    }
    public function onConnect($serv, $fd, $from_id) {
    $serv->send($fd, "Hello {$fd}!");
    }
    public function onReceive(swoole_server $serv, $fd, $from_id, $data) {
    echo "Get Message From Client {$fd}:{$data}\n";
    $res['result'] = 'success';
    $serv->send($fd, json_encode($res));
    $serv->task($data);
    }
    public function onTask(swoole_server $serv, $task_id, $from_id, $data) {
    swoole_timer_tick(30000, function($timer) use ($task_id) {
    $memPercent = $this->getMemoryUsage();
    echo date('Y-m-d H:i:s') . '当前内存使用率:' . $memPercent . "\n";
    });
    }
    public function onFinish(swoole_server $serv, $task_id, $data) {
    // ...
    }
    public function onClose($serv, $fd, $from_id) {
    echo "Client {$fd} close connection\n";
    }
    public function stop() {
    $this->serv->stop();
    }
    private function getMemoryUsage() {
    if (false === ($str = @file("/proc/meminfo"))) return false;
    $str = implode("", $str);
    preg_match_all("/MemTotal\s{0,}\:+\s{0,}([\d\.]+).+?MemFree\s{0,}\:+\s{0,}([\d\.]+).+?Cached\s{0,}\:+\s{0,}([\d\.]+).+?SwapTotal\s{0,}\:+\s{0,}([\d\.]+).+?SwapFree\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buf);
    $memTotal = round($buf[1][0]/1024, 2);
    $memFree = round($buf[2][0]/1024, 2);
    $memUsed = $memTotal - $memFree;
    $memPercent = (floatval($memTotal) != 0) ? round($memUsed/$memTotal*100, 2) : 0;
    return $memPercent;
    }
    }

    文件:src/App/TaskServer.php

    false,
    ];
    $ser = new Task($opt);
    $ser->start();

    文件:src/App/TaskClient.php

    client = new swoole_client(SWOOLE_SOCK_TCP);
    }
    public function connect() {
    if (!$this->client->connect("127.0.0.1", 9506, 1)) {
    echo "Error: {$this->client->errMsg}[{$this->client->errCode}]\n";
    }
    fwrite(STDOUT, "请输入消息 Please input msg:");
    $msg = trim(fgets(STDIN));
    $this->client->send($msg);
    $message = $this->client->recv();
    echo "Get Message From Server:{$message}\n";
    }
    }
    $client = new Client();
    $client->connect();

    验证效果

  • 启动服务端

    在命令行执行:

    php taskServer.php
  • 客户端输入

    在另一个命令行窗口执行:

    php taskClient.php

    输入消息:Please input msg: hello

  • 服务端返回

    应用将输出类似以下内容:

    Get Message From Server: {"result":"success"}
  • 定时任务输出

    每隔30秒,服务端将输出当前内存使用率的信息。

  • 通过以上步骤,可以验证Swoole毫秒定时器的功能是否正常工作。

    转载地址:http://pgdk.baihongyu.com/

    你可能感兴趣的文章
    Node-RED安装图形化节点dashboard实现订阅mqtt主题并在仪表盘中显示温度
    查看>>
    Node-RED怎样导出导入流程为json文件
    查看>>
    Node-RED订阅MQTT主题并调试数据
    查看>>
    Node-RED通过npm安装的方式对应卸载
    查看>>
    node-request模块
    查看>>
    node-static 任意文件读取漏洞复现(CVE-2023-26111)
    查看>>
    Node.js 8 中的 util.promisify的详解
    查看>>
    node.js debug在webstrom工具
    查看>>
    Node.js HTTP模块详解:创建服务器、响应请求与客户端请求
    查看>>
    Node.js RESTful API如何使用?
    查看>>
    node.js url模块
    查看>>
    Node.js Web 模块的各种用法和常见场景
    查看>>
    Node.js 之 log4js 完全讲解
    查看>>
    Node.js 函数是什么样的?
    查看>>
    Node.js 函数计算如何突破启动瓶颈,优化启动速度
    查看>>
    Node.js 切近实战(七) 之Excel在线(文件&文件组)
    查看>>
    node.js 初体验
    查看>>
    Node.js 历史
    查看>>
    Node.js 在个推的微服务实践:基于容器的一站式命令行工具链
    查看>>
    Node.js 实现类似于.php,.jsp的服务器页面技术,自动路由
    查看>>