Maison >développement back-end >tutoriel php >Méthode d'implémentation du minuteur PHP multitâche de deuxième niveau

Méthode d'implémentation du minuteur PHP multitâche de deuxième niveau

不言
不言original
2018-06-01 09:56:481686parcourir

Cet article présente principalement la méthode d'implémentation du minuteur multitâche PHP de deuxième niveau. Il est très bon et a une certaine valeur de référence. Les amis dans le besoin peuvent se référer à la

Description.

Lorsque je déployais récemment crontab dans mon entreprise, je me suis soudainement demandé si je pouvais utiliser PHP pour implémenter un minuteur. La granularité serait descendue au deuxième niveau, car crontab peut atteindre. au niveau minute au maximum. J'ai aussi fait quelques recherches en même temps. Au bout d'un moment, il n'y a pas beaucoup de timers implémentés en PHP. L'extension Swoole implémente un timer au niveau de la milliseconde, ce qui est très efficace, mais après tout, c'est le cas. pas écrit en code PHP pur, j'ai donc finalement envisagé d'utiliser PHP pour implémenter une catégorie de minuterie pour référence d'apprentissage.

Implémentation

Lors de l'implémentation du code du timer, deux extensions fournies avec le système PHP sont utilisées

Pcntl - Multi -extension de processus :

Permet principalement à PHP d'ouvrir de nombreux sous-processus en même temps et de traiter certaines tâches en parallèle.

Spl - SplMinHeap - Petit tas supérieur

Une petite structure de données en tas supérieur Lors de l'implémentation d'un minuteur, l'utilisation de cette structure est très efficace. est O (logN). Les minuteries comme Libevent ont également utilisé rbtree avant d'adopter cette structure de données après la version 1.4. Si une liste chaînée ou un tableau fixe est utilisé, chaque insertion ou suppression devra peut-être être parcourue ou triée à nouveau. .

Processus

Instructions

1. Définissez la structure de la minuterie et les paramètres qui s'y trouvent.
2. Ensuite, enregistrez-les tous dans notre classe timer Timer.
3. Appelez la méthode de surveillance de la classe timer pour démarrer la surveillance. 4. Le processus de surveillance est une boucle while sans fin, vérifiant constamment si le haut du tas de temps a expiré. Au départ, j'avais envisagé de boucler pour vérifier une fois par seconde, mais j'ai ensuite pensé que ce serait un problème de boucler pour vérifier une fois par seconde. Si c'est le cas lorsque nous dormons (1), le minuteur a expiré, nous ne pouvons donc pas l'exécuter avec précision tout de suite, et il peut y avoir un risque de retard, nous utilisons donc toujours usleep (1000) pour le voir en millisecondes et suspendre le processus. pour réduire la charge CPU 🎜>
également testés et comparés Dans un cas extrême, si les 1 000 minuteries expirent en 1 seconde en même temps, il ne faut que 0,126 seconde pour ajuster le tas de temps. Ce n'est pas un problème, mais à chaque fois qu'une minuterie est ajustée, un processus enfant doit être démarré, ce qui peut prendre du temps, il est possible que ces 1 000 ne puissent pas être traités en 1 seconde, ce qui affectera la surveillance pour continuer à se déclencher la prochaine fois, mais si le processus enfant n'est pas démarré, par exemple, il peut toujours être traité par exécution directe. . . . Bien sûr, il doit y avoir une meilleure solution, mais c'est la seule chose à laquelle je pense pour le moment.

Recommandations associées :

idées d'implémentation du cache de base de données 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[&#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;;
   }
 }

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn