프로젝트 개발 중에 예정된 작업에 대한 비즈니스 요구 사항이 있는 경우 Linux의 crontab을 사용하여 이를 해결하지만 최소 세분성은 필요한 세분성인 경우입니다. 두 번째 수준이나 심지어 밀리초 수준에서도 crontab은 이를 만족시킬 수 없습니다. 다행히 swoole은 강력한 밀리초 타이머를 제공합니다.
추천 학습: swoole tutorial
응용 시나리오 예시
우리는 할 수 있습니다 다음과 같은 시나리오가 발생합니다:
● 시나리오 1: 30초마다 로컬 메모리 사용량 가져오기
● 시나리오 2: 2분 후에 보고서 전송 작업 실행# 🎜🎜 #
● 시나리오 3: 매일 아침 2시에 타사 인터페이스를 정기적으로 요청합니다. 인터페이스가 어떤 이유로든 응답하지 않거나 데이터가 반환되지 않으면 작업이 중지됩니다. , 요청은 5분 후에도 계속 시도됩니다. 이 인터페이스의 경우 5번의 시도 후에도 계속 실패하면 작업이 중지됩니다. 위의 세 가지 시나리오를 모두 예약된 범주로 분류할 수 있습니다. 작업.Swoole 밀리초 타이머
Swoole은 비동기 밀리초 타이머 기능을 제공합니다.swoole_timer_tick( int $ msec, 호출 가능 $callback)
: 자바스크립트의 setInterval()
과 유사하게 간격 시계 타이머를 설정하고 $msec 밀리초마다 $callback을 실행합니다. swoole_timer_tick(int $msec, callable $callback)
:设置一个间隔时钟定时器,每隔$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()
。
解决方案
对于场景一,经常用在系统检测统计方面,实时性要求比较高,但又能控制好频率,多用于后台服务器性能监控,可以生成可视化图表。可以是30秒获取一次内存使用率,也可以是10秒,而crontab最小粒度只能设置为1分钟。
swoole_timer_tick(30000, function($timer) use ($task_id) { // 启用定时器,每30秒执行一次 $memPercent = $this->getMemoryUsage(); //计算内存使用率 echo date('Y-m-d H:i:s') . '当前内存使用率:'.$memPercent."\n"; });
对于场景二,直接定义xx时间后执行某项任务的话,貌似crontab比较困难,而使用swoole的swoole_timer_after可以实现:
swoole_timer_after(120000, function() use ($str) { //2分钟后执行 $this->sendReport(); //发送报表 echo "send report, $str\n"; });
对于场景三,用来作尝试请求,请求失败后继续,如果成功则停止请求。用crontab也能解决,但是比较傻,比如设置每隔5分钟请求一次,不管成功会失败都会去执行一次。而用swoole定时器则智能多了。
swoole_timer_tick(5*60*1000, function($timer) use ($url) { // 启用定时器,每5分钟执行一次 $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"; } });
示例代码
新建文件srcAppTask.php:
<?php namespace Helloweba\Swoole; use swoole_server; /** * 任务调度 */ class Task { protected $serv; protected $host = '127.0.0.1'; protected $port = 9506; // 进程名称 protected $taskName = 'swooleTask'; // PID路径 protected $pidPath = '/run/swooletask.pid'; // 设置运行时参数 protected $options = [ 'worker_num' => 4, //worker进程数,一般设置为CPU数的1-4倍 'daemonize' => true, //启用守护进程 'log_file' => '/data/log/swoole-task.log', //指定swoole错误日志文件 'log_level' => 0, //日志级别 范围是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR 'dispatch_mode' => 1, //数据包分发策略,1-轮询模式 'task_worker_num' => 4, //task进程的数量 'task_ipc_mode' => 3, //使用消息队列通信,并设置为争抢模式 ]; public function __construct($options = []) { date_default_timezone_set('PRC'); // 构建Server对象,监听127.0.0.1:9506端口 $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() { // Run worker $this->serv->start(); } public function onStart($serv) { // 设置进程名 cli_set_process_title($this->taskName); //记录进程id,脚本实现自动重启 $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"; //$this->writeLog('接收客户端参数:'.$fd .'-'.$data); $res['result'] = 'success'; $serv->send($fd, json_encode($res)); // 同步返回消息给客户端 $serv->task($data); // 执行异步任务 } /** * @param $serv swoole_server swoole_server对象 * @param $task_id int 任务id * @param $from_id int 投递任务的worker_id * @param $data string 投递的数据 */ public function onTask(swoole_server $serv, $task_id, $from_id, $data) { swoole_timer_tick(30000, function($timer) use ($task_id) { // 启用定时器,每30秒执行一次 $memPercent = $this->getMemoryUsage(); echo date('Y-m-d H:i:s') . '当前内存使用率:'.$memPercent."\n"; }); } /** * @param $serv swoole_server swoole_server对象 * @param $task_id int 任务id * @param $data string 任务返回的数据 */ 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() { // MEMORY 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); //preg_match_all("/Buffers\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buffers); $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; } }
我们以场景一为例,在onTask启用定时任务,每隔30秒计算一次内存使用率。实际应用中可以把计算好的内存按时间写入数据库等存储中,然后可以根据前端需求用来渲染成统计图表,如:
接着服务端代码 publictaskServer.php :
<?php require dirname(__DIR__) . '/vendor/autoload.php'; use Helloweba\Swoole\Task; $opt = [ 'daemonize' => false ]; $ser = new Task($opt); $ser->start();
客户端代码 publictaskClient.php :
<?php class Client { private $client; public function __construct() { $this->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();
验证效果
1.启动服务端:
php taskServer.php
swoole_timer_after(int $after_time_ms, Mixed $callback_function)
: 지정된 시간 $after_time_ms
이후에 $callback_function
을 실행합니다. 자바스크립트의 setTimeout()
과 유사합니다.
swoole_timer_clear(int $timer_id
): javascript의 clearInterval()
과 유사하게 지정된 ID를 가진 타이머를 삭제합니다.
시나리오 1의 경우 실시간 요구 사항이 상대적으로 높지만 빈도가 높은 경우에 자주 사용됩니다. 잘 제어할 수 있으며 주로 백그라운드 서버 성능 모니터링에 사용되며 시각적 차트를 생성할 수 있습니다. 메모리 사용량은 30초마다 또는 10초마다 얻을 수 있지만 crontab의 최소 단위는 1분으로만 설정할 수 있습니다.
[root@localhost public]# php taskClient.php
시나리오 2의 경우 xx 이후 특정 작업을 직접 정의하면 crontab이 더 어려울 것 같으니, swoole의 swoole_timer_after 실현 가능:
Get Message From Server:{"result":"success"} [root@localhost public]#시나리오 3의 경우 요청이 실패하면 계속해서 요청을 중지하는 데 사용됩니다. crontab을 이용해서 해결할 수도 있지만, 예를 들어 5분마다 요청을 설정하면 성공, 실패에 관계없이 실행됩니다. Swoole 타이머를 사용하는 것이 훨씬 더 똑똑합니다. #🎜🎜#rrreee#🎜🎜# #🎜🎜##🎜🎜#샘플 코드#🎜🎜##🎜🎜#새 파일 srcAppTask.php: #🎜🎜#rrreee#🎜🎜# #🎜🎜##🎜🎜# #🎜🎜##🎜🎜# 시나리오 1을 예로 들어 onTask에서 예약된 작업을 활성화하고 30초마다 메모리 사용량을 계산해 보겠습니다. 실제 애플리케이션에서는 계산된 메모리를 시간을 기준으로 데이터베이스나 기타 저장소에 기록한 다음 다음과 같은 프런트 엔드 요구 사항에 따라 통계 차트를 렌더링하는 데 사용할 수 있습니다. #🎜🎜##🎜🎜##🎜🎜##🎜 🎜 #그럼 서버 코드 publictaskServer.php :#🎜🎜#rrreee#🎜🎜# #🎜🎜##🎜🎜# #🎜🎜##🎜🎜#클라이언트 코드 publictaskClient.php :#🎜🎜#rrreee#🎜🎜# #🎜🎜# #🎜🎜# 효과 확인#🎜🎜##🎜🎜#1 서버를 시작합니다. #🎜🎜##🎜🎜#
php taskServer.php
#🎜🎜##🎜🎜# #🎜 🎜##🎜🎜 #2. 클라이언트 입력: #🎜🎜##🎜🎜#다른 명령줄 창을 열고 실행 #🎜🎜#rrreee#🎜🎜#msg를 입력하세요: hello#🎜🎜#rrreee#🎜🎜# # 🎜 🎜##🎜🎜#3. 서버가 다음을 반환합니다. #🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#위 그림의 결과가 반환되면 예약된 작업이 정상적으로 실행되고 있는 것입니다. 그리고 우리는 모든 A 메시지가 30초마다 출력된다는 것을 알게 될 것입니다. #🎜🎜#위 내용은 php Swoole은 밀리초 수준의 예약된 작업을 구현합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!