描写
最近在公司陈设crontab的时辰,突发奇想是否可以用PHP去实现一个按时器,颗粒度到秒级就好,由于crontab最多到分钟级别,同时也调研了一下用PHP去实现的按时器还真不太多,Swoole 扩展内里到实现了一个毫秒级的按时器很高效,但事实不是纯PHP代码写的,以是最后照旧思量用PHP去实现一个按时器类,以供学衔拷寮。
实现
在实现按时器代码的时辰,用到了PHP体系自带的两个扩展
Pcntl - 多历程扩展 :
首要就是让PHP可以同时开启许多子历程,并行的行止理赏罚一些使命。
Spl - SplMinHeap - 小顶堆
一个小顶堆数据布局,在实现按时器的时辰,回收这种布局服从照旧不错的,插入、删除的时刻伟大度都是 O(logN) ,像 libevent 的按时器也在 1.4 版本往后回收了这种数据布局之前用的是 rbtree,假如要是行使链表可能牢靠的数组,每次插入、删除也许都必要从头遍历可能排序,照旧有必然的机能题目的。
流程
声名
1、界说按时器布局,有什么参数之类的.
2、然后所有注册进我们的按时器类 Timer.
3、挪用按时器类的monitor要领,开始举办监听.
4、监听进程就是一个while死轮回,不绝的去看时刻堆的堆顶是否到期了,原来思量每秒轮回看一次,其后一想每秒轮回看一次照旧有点题目,假如正亏得我们sleep(1)的时辰按时器有到期的了,那我们就不能顿时去精准执行,也许会有延时的风险,以是照旧回收 usleep(1000) 毫秒级的去看而且也可以将历程挂起减轻 CPU 负载.
代码
<div class="jb51code">
<pre class="brush:php;">
/***
- 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) . "秒rn" : '';
}
}
实例
insert(array('expire' => 3,'repeat' => true,'action' => function(){
echo '3秒 - 一再 - hello world' . "rn";
}));
//注册 - 3s - 一再触发
$timer->insert(array('expire' => 3,'action' => function(){
echo '3秒 - 一再 - gogo' . "rn";
}));
//注册 - 6s - 触发一次
$timer->insert(array('expire' => 6,'repeat' => false,'action' => function(){
echo '6秒 - 一次 - hello xxxx' . "rn";
}));
//监听
$timer->monitor(false);
执行功效
也测试过较量极度的环境,同时1000个按时器1s所有到期,时刻堆所有调解完仅需 0.126s 这是没题目的,可是每调解完一个按时器就必要去开启一个子历程,这块也许较量耗时了,有也许1s处理赏罚不完这1000个,就会影响下次监听继承触发,可是不开启子历程,好比直接执行应该照旧可以处理赏罚完的。。。。虽然必定有更好的要领,今朝只能想到这样。
总结
以上所述是小编给各人先容的PHP 多使命秒级按时器的实现要领,但愿对各人有所辅佐,假如各人有任何疑问接待给我留言,小编会实时回覆各人的!
(编辑:湖南网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|