加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

PHP 多使命秒级按时器的实现要领

发布时间:2021-05-15 18:57:30 所属栏目:编程 来源:网络整理
导读:描写 最近在公司陈设crontab的时辰,突发奇想是否可以用PHP去实现一个按时器,颗粒度到秒级就好,由于crontab最多到分钟级别,同时也调研了一下用PHP去实现的按时器还真不太多,Swoole 扩展内里到实现了一个毫秒级的按时器很高效,但事实不是纯PHP代码写的,

描写

最近在公司陈设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 多使命秒级按时器的实现要领,但愿对各人有所辅佐,假如各人有任何疑问接待给我留言,小编会实时回覆各人的!

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读