PHP多任务秒级定时器的实现方法-php教程

资源魔 30 0
形容

比来正在公司部署crontab的时分,突发奇想能否能够用PHP去完成一个按时器,颗粒度到秒级就好,由于crontab最多到分钟级别,同时也调研了一下用PHP去完成的按时器还真没有太多,Swoole 扩大外面到完成了一个毫秒级的按时器很高效,但究竟结果没有是纯PHP代码写的,以是最初仍是思考用PHP去完成一个按时器类,以供学习参考。

完成

正在完成按时器代码的时分,用到了PHP零碎自带的两个扩大

Pcntl - 多过程扩大 :

次要就是让PHP能够同时开启不少子过程,并行的行止理一些义务。

Spl - SplMinHeap - 小顶堆

一个小顶堆数据构造,正在完成按时器的时分,采纳这类构造效率仍是没有错的,拔出、删除了的工夫复杂度都是 O(logN) ,像 libevent 的按时器也正在 1.4 版本当前采纳了这类数据构造以前用的是 rbtree,假如要是应用链表或许固定的数组,每一次拔出、删除了可能都需求从新遍历或许排序,仍是有肯定的功能成绩的。

流程

ee6901e9d45e395f3a4a47c8ba91cc0.png

阐明

一、界说按时器构造,有甚么参数之类的.

二、而后全副注册进咱们的按时器类 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);

执行后果

fc7b9bbe9fbd89a17f2087f6241d1c8.png

也测试过比拟极其的状况,同时1000个按时器1s全副到期,工夫堆全副调整完仅需 0.126s 这是没成绩的,然而每一调整完一个按时器就需求去开启一个子过程,这块可能比拟耗时了,有可能1s解决没有完这1000个,就会影响下次监听持续触发,然而没有开启子过程,比方间接执行应该仍是能够解决完的。。。。当然一定有更好的办法,今朝只能想到这样。

以上就是PHP多义务秒级按时器的完成办法的具体内容,更多请存眷资源魔其它相干文章!

标签: php php开发教程 php开发资料 php开发自学

抱歉,评论功能暂时关闭!