本文共 5362 字,大约阅读时间需要 17 分钟。
项目开发中,如果有定时任务的业务需求,可以选择使用Linux的crontab工具来处理。但需要注意的是,crontab的最小粒度是分钟级别,对于需要秒级或毫秒级定时任务来说,它就不足以满足需求。幸运的是,Swoole提供了强大的毫秒定时器功能,可以更灵活地满足各种定时任务的需求。
在实际项目中,我们可能会遇到以下几种定时任务的场景:
场景一:每隔30秒获取一次本机内存使用率
这种场景常见于系统性能监控中。虽然实时性要求较高,但又能控制好执行频率,适合后台服务器性能监控,可以生成可视化图表。可以是30秒获取一次内存使用率,也可以是10秒,具体取决于业务需求。场景二:2分钟后执行报表发送任务
如果需要在特定时间执行一次性任务,crontab虽然可以实现,但比较繁琐。使用Swoole的定时器可以直接定义执行时间,实现更简便。场景三:每天凌晨2点钟定时请求第三方接口
这种场景需要考虑接口响应情况。可以设置定时器在5分钟后重试,直到成功或达到最大尝试次数后停止。Swoole提供了多种异步毫秒定时器函数,支持以毫秒级精度执行定时任务:
swoole_timer_tick(int $msec, callable $callback)
setInterval()。 swoole_timer_after(int $after_time_ms, mixed $callback_function)
setTimeout()。 swoole_timer_clear(int $timer_id)
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/