>  기사  >  백엔드 개발  >  PHP 다중 작업 2차 타이머 구현 방법

PHP 다중 작업 2차 타이머 구현 방법

藏色散人
藏色散人앞으로
2020-01-15 17:46:552537검색

Description

최근 회사에서 crontab을 배포할 때 갑자기 PHP를 사용하여 타이머를 구현할 수 있는지 궁금했습니다. crontab은 어떻게 하면 분 수준까지만 도달할 수 있는지도 연구했기 때문입니다. 실제로 구현된 타이머가 많지 않습니다. Swoole 확장은 밀리초 수준의 타이머를 구현하는데 이는 매우 효율적이지만 결국 순수한 PHP 코드로 작성되지 않았기 때문에 결국 고려했습니다. PHP를 사용하여 학습용 타이머 클래스를 구현합니다.

구현

타이머 코드를 구현할 때 PHP 시스템과 함께 제공되는 두 가지 확장이 사용됩니다.

Pcntl - 다중 프로세스 확장:

주된 목적은 PHP가 동시에 많은 하위 프로세스를 시작할 수 있도록 하는 것입니다. 시간을 들여 일부 작업을 병렬로 처리합니다.

Spl - SplMinHeap - 작은 MinHeap

타이머를 구현할 때 이 구조를 사용하면 libevent와 마찬가지로 삽입 및 삭제의 시간 복잡도가 O(logN)입니다. 타이머도 채택되었습니다. 버전 1.4 이후에는 이 데이터 구조가 rbtree를 사용했습니다. 연결 목록이나 고정 배열을 사용하는 경우 각 삽입 또는 삭제를 다시 순회하거나 정렬해야 할 수 있으며 여전히 특정 성능 문제가 있습니다.

Process

PHP 다중 작업 2차 타이머 구현 방법

Instructions

1. 타이머 구조, 매개변수 등을 정의합니다.

2. 그런 다음 타이머 클래스에 모두 등록합니다.

3. 모니터링을 시작하려면 디바이스 클래스의 모니터 메서드를 사용하세요.

4. 모니터링 프로세스는 무한 while 루프로, 원래는 1초에 한 번씩 루프가 만료되었는지 지속적으로 확인합니다. 1초마다 반복하는 문제가 있는데, 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[&#39;timeout&#39;] < $value2[&#39;timeout&#39;]) {
      return 1;
    }
    return 0;
  }
  /**
  * 插入节点
  * @param mixed $value
  */
  public function insert($value)
  {
    $value[&#39;timeout&#39;] = time() + $value[&#39;expire&#39;];
    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[&#39;timeout&#39;] <= time()) {
        //出堆或入堆
        $node[&#39;repeat&#39;] ? $this->insert($this->extract()) : $this->extract();
        $hit = 1;
        //开启子进程
        if (pcntl_fork() == 0) {
          empty($node[&#39;action&#39;]) ? &#39;&#39; : call_user_func($node[&#39;action&#39;]);
          exit(0);
        }
        //忽略子进程,子进程退出由系统回收
        pcntl_signal(SIGCLD, SIG_IGN);
      } else {
        break;
      }
    }
    $t2 = microtime(true);
    echo ($debug && $hit) ? &#39;时间堆 - 调整耗时: &#39; . round($t2 - $t1, 3) . "秒\r\n" : &#39;&#39;;
  }
}
Instance

$timer = new Timer();
//注册 - 3s - 重复触发
$timer->insert(array(&#39;expire&#39; => 3, &#39;repeat&#39; => true, &#39;action&#39; => function(){
  echo &#39;3秒 - 重复 - hello world&#39; . "\r\n";
}));
//注册 - 3s - 重复触发
$timer->insert(array(&#39;expire&#39; => 3, &#39;repeat&#39; => true, &#39;action&#39; => function(){
  echo &#39;3秒 - 重复 - gogo&#39; . "\r\n";
}));
//注册 - 6s - 触发一次
$timer->insert(array(&#39;expire&#39; => 6, &#39;repeat&#39; => false, &#39;action&#39; => function(){
  echo &#39;6秒 - 一次 - hello xxxx&#39; . "\r\n";
}));
//监听
$timer->monitor(false);
Execution results

동시에 1초 동안의 타이머가 만료되면 모든 시간 스택을 조정하는 데 0.126초만 걸립니다. 이는 문제가 되지 않지만 타이머가 조정될 때마다 하위 프로세스를 시작해야 할 수 있습니다. 1초 안에 1,000번을 처리하지 못할 수도 있으므로 다음에 계속 트리거하도록 모니터링에 영향을 주지만, 예를 들어 직접 실행을 통해 하위 프로세스를 시작하지 않고도 프로세스를 완료할 수 있습니다. . . . . 물론 더 좋은 방법이 있을 텐데 현재로서는 이것밖에 생각이 나지 않습니다. PHP 다중 작업 2차 타이머 구현 방법

위 내용은 PHP 다중 작업 2차 타이머 구현 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제