Heim  >  Artikel  >  Backend-Entwicklung  >  Implementierungsmethode des PHP-Multitasking-Timers der zweiten Ebene

Implementierungsmethode des PHP-Multitasking-Timers der zweiten Ebene

藏色散人
藏色散人nach vorne
2020-01-15 17:46:552604Durchsuche

Beschreibung

Als ich kürzlich Crontab in meinem Unternehmen einsetzte, fragte ich mich plötzlich, ob ich PHP verwenden könnte, um einen Timer mit einer Granularität von Sekunden zu implementieren, da Crontab nur aktiv sein kann Gleichzeitig habe ich auch recherchiert, dass in PHP nicht viele Timer implementiert sind, was sehr effizient ist, aber schließlich nicht in reinem PHP-Code geschrieben ist Daher habe ich am Ende immer noch darüber nachgedacht, PHP zu verwenden, um eine Timer-Klasse als Lernreferenz zu implementieren.

Implementierung

Bei der Implementierung des Timer-Codes werden zwei Erweiterungen verwendet, die mit dem PHP-System geliefert werden

Pcntl - Multi-Process-Erweiterung:

Der Hauptzweck besteht darin, PHP zu ermöglichen, viele Unterprozesse gleichzeitig zu öffnen und einige Aufgaben parallel zu verarbeiten.

Spl - SplMinHeap - Kleiner oberer Heap

Bei der Implementierung eines Timers ist die Zeitkomplexität des Einfügens und Löschens sehr gering ist O(logN). Timer wie libevent verwendeten rbtree nach Version 1.4 ebenfalls. Wenn eine verknüpfte Liste oder ein festes Array verwendet wird, muss möglicherweise jedes Einfügen oder Löschen erneut durchlaufen oder sortiert werden .

Prozess

Implementierungsmethode des PHP-Multitasking-Timers der zweiten Ebene

Erklärung

1. Definieren Sie die Timerstruktur, was ist dort Parameter und dergleichen.

Dann registrieren Sie sie alle in unserer Timer-Klasse Timer.

3. Rufen Sie die Monitor-Methode der Timer-Klasse auf und starten Sie die Überwachung.

4. Der Überwachungsprozess ist eine endlose While-Schleife, bei der ständig überprüft wird, ob die Spitze des Zeitheaps abgelaufen ist. Ursprünglich hatte ich darüber nachgedacht, eine Schleife einmal pro Sekunde durchzuführen, dachte dann aber, dass es ein Problem wäre, eine Schleife durchzuführen, um einmal jede Sekunde zu prüfen. Wenn es während unseres Schlafs passiert (1) Wenn der Timer abläuft, können wir ihn nicht sofort genau ausführen und es besteht möglicherweise die Gefahr einer Verzögerung. Daher verwenden wir weiterhin usleep (1000), um ihn in Millisekunden anzuzeigen und den Vorgang anzuhalten Reduzieren Sie die CPU-Last.

Code

/***
* 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;;
  }
}

Instanz

$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);

Ausführungsergebnis

Implementierungsmethode des PHP-Multitasking-Timers der zweiten Ebene

Ich habe auch eine Extremsituation getestet. Gleichzeitig laufen 1000 Timer in 1 Sekunde ab und es dauert nur 0,126 Sekunden, um alle Zeitstapel anzupassen Wird ein untergeordneter Prozess angepasst, kann dies zeitaufwändig sein. Es kann sein, dass die 1.000 nicht in 1 Sekunde verarbeitet werden können, was sich jedoch auf die weitere Auslösung des untergeordneten Prozesses auswirkt Beispielsweise sollte die direkte Ausführung die Verarbeitung dennoch abschließen können. . . . Natürlich muss es einen besseren Weg geben, aber das ist das Einzige, was mir im Moment einfällt.

Das obige ist der detaillierte Inhalt vonImplementierungsmethode des PHP-Multitasking-Timers der zweiten Ebene. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:csdn.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen