比来正在公司部署crontab的时分,突发奇想能否能够用PHP去完成一个按时器,颗粒度到秒级就好,由于crontab最多到分钟级别,同时也调研了一下用PHP去完成的按时器还真没有太多,Swoole 扩大外面到完成了一个毫秒级的按时器很高效,但究竟结果没有是纯PHP代码写的,以是最初仍是思考用PHP去完成一个按时器类,以供学习参考。
完成
正在完成按时器代码的时分,用到了PHP零碎自带的两个扩大
Pcntl - 多过程扩大 :
次要就是让PHP能够同时开启不少子过程,并行的行止理一些义务。
Spl - SplMinHeap - 小顶堆
一个小顶堆数据构造,正在完成按时器的时分,采纳这类构造效率仍是没有错的,拔出、删除了的工夫复杂度都是 O(logN) ,像 libevent 的按时器也正在 1.4 版本当前采纳了这类数据构造以前用的是 rbtree,假如要是应用链表或许固定的数组,每一次拔出、删除了可能都需求从新遍历或许排序,仍是有肯定的功能成绩的。
流程
阐明
一、界说按时器构造,有甚么参数之类的.
二、而后全副注册进咱们的按时器类 Timer.
三、挪用按时器类的monitor办法,开端进行监听.
四、监听进程就是一个while死轮回,一直的去看工夫堆的堆顶能否到期了,原本思考每一秒轮回看一次,起初一想每一秒轮回看一次仍是有点成绩,假如正好正在咱们sleep(1)的时分按时器有到期的了,那咱们就不克不及即刻去精准执行,可能会有延时的危险,以是仍是采纳 usleep(1000) 毫秒级的去看而且也能够将过程挂起加重 CPU 负载.
代码
/*** * Class Timer */ class Timer extends SplMinHeap { /** * 比拟根节点以及新拔出节点巨细 * @param mixed $value1 * @param mixed $value2 * @return int */ protected function compare($value1, $value2) { if ($value1['timeout'] > $value2['timeout']) { return -1; } if ($value1['timeout'] < $value2['timeout']) { return 1; } return 0; } /** * 拔出节点 * @param mixed $value */ public function insert($value) { $value['timeout'] = time() + $value['expire']; parent::insert($value); } /** * 监听 * @param bool $debug */ public function monitor($debug = false) { while (!$this->isEmpty()) { $this->exec($debug); usleep(1000); } } /** * 执行 * @param $debug */ private function exec($debug) { $hit = 0; $t1 = microtime(true); while (!$this->isEmpty()) { $node = $this->top(); if ($node['timeout'] <= time()) { //出堆或入堆 $node['repeat'] ? $this->insert($this->extract()) : $this->extract(); $hit = 1; //开启子过程 if (pcntl_fork() == 0) { empty($node['action']) ? '' : call_user_func($node['action']); exit(0); } //疏忽子过程,子过程加入由零碎收受接管 pcntl_signal(SIGCLD, SIG_IGN); } else { break; } } $t2 = microtime(true); echo ($debug && $hit) ? '工夫堆 - 调整耗时: ' . round($t2 - $t1, 3) . "秒\r\n" : ''; } }
实例
$timer = new Timer(); //注册 - 3s - 反复触发 $timer->insert(array('expire' => 3, 'repeat' => true, 'action' => function(){ echo '3秒 - 反复 - hello world' . "\r\n"; })); //注册 - 3s - 反复触发 $timer->insert(array('expire' => 3, 'repeat' => true, 'action' => function(){ echo '3秒 - 反复 - gogo' . "\r\n"; })); //注册 - 6s - 触发一次 $timer->insert(array('expire' => 6, 'repeat' => false, 'action' => function(){ echo '6秒 - 一次 - hello xxxx' . "\r\n"; })); //监听 $timer->monitor(false);
执行后果
也测试过比拟极其的状况,同时1000个按时器1s全副到期,工夫堆全副调整完仅需 0.126s 这是没成绩的,然而每一调整完一个按时器就需求去开启一个子过程,这块可能比拟耗时了,有可能1s解决没有完这1000个,就会影响下次监听持续触发,然而没有开启子过程,比方间接执行应该仍是能够解决完的。。。。当然一定有更好的办法,今朝只能想到这样。
以上就是PHP多义务秒级按时器的完成办法的具体内容,更多请存眷资源魔其它相干文章!
标签: php php开发教程 php开发资料 php开发自学
抱歉,评论功能暂时关闭!