Maison >développement back-end >tutoriel php >Une introduction aux coroutines et au blocage en PHP
Cet article vous présente principalement une certaine compréhension et réflexion sur les coroutines et le blocage en PHP. L'article le présente en détail à travers un exemple de code. Il a une certaine valeur d'apprentissage de référence pour que tous les amis qui en ont besoin apprennent. avec l'éditeur ci-dessous.
Avant-propos
Cet article vous présente principalement la compréhension et la réflexion sur les coroutines et le blocage en PHP, et le partage pour votre référence et votre étude . Pas grand chose à dire ci-dessous, jetons un œil à l'introduction détaillée :
Processus, thread, coroutine
À propos du processus. , les fils de discussion et les coroutines, il existe des blogs ou des ressources d'apprentissage très détaillés et riches. Je n'entrerai pas dans les détails ici, je présenterai brièvement ces choses ici.
Le processus a son propre tas et sa pile indépendants. Il ne partage ni le tas ni la pile. Le processus est planifié par le système d'exploitation.
Les threads ont leur propre pile indépendante et leur tas partagé. Le tas est partagé mais la pile n'est pas partagée. Les threads sont également planifiés par le système d'exploitation (les threads standard le sont).
Les coroutines partagent le tas comme les threads, mais ne partagent pas les piles. Les coroutines sont planifiées explicitement par les programmeurs dans le code de la coroutine.
Implémentation de base du rendement de la coroutine en PHP
L'implémentation fondamentale du rendement est de génère la classe Iterator, et la classe iterator est l'implémentation de l'interface iterator :
Generator implements Iterator { public mixed current ( void ) // 返回当前产生的值 public mixed key ( void ) // 返回当前产生的键 public void next ( void ) // 生成器继续执行 public void rewind ( void ) // 重置迭代器,如果迭代已经开始了,这里会抛出一个异常。 // renwind的执行将会导致第一个yield被执行, 并且忽略了他的返回值. public mixed send ( mixed $value ) // 向生成器中传入一个值,并且当做 yield 表达式的结果,然后继续执行生成器。如果当这个方法被调用时,生成器 // 不在 yield 表达式,那么在传入值之前,它会先运行到第一个 yield 表达式。 public void throw ( Exception $exception ) // 向生成器中抛入一个异常 public bool valid ( void ) // 检查迭代器是否被关闭 public void __wakeup ( void ) // 序列化回调,抛出一个异常以表示生成器不能被序列化。 }
Vous pouvez vous référer à la documentation officielle PHP pour l'analyse ci-dessus.
http://php.net/manual/zh/clas...
Et ce document détaillé :
http://www.jb51.net/ article /39424_all.htm
Je vais donner un exemple basé sur la planification multitâche coroutine qu'il a mise en œuvre et parler de certaines de mes réflexions sur le blocage.
Exemple de personnalisation de tâches d'exécution planifiées simples :
(Cet exemple doit s'appuyer sur le code de planification de coroutine implémenté par Brother Niao ci-dessus )
class timer { private $start = 0; // 定时开始时间 private $timer; // 间隔的时间差,单位秒 private $value = 0; // 产生的结果值 private $callback; // 异步回调 private $isEnd = false; // 当前定时器任务是否结束 public function __construct($timer,callable $callback) { $this->start = time(); $this->timer = $timer; $this->callback = $callback; } public function run() { if($this->valid()) { $callback = $this->callback; $callback($this->value ++,$this); $this->start = time(); } } /** * 定时执行检查 */ public function valid() { $end = time(); if($end - $this->start >= $this->timer) { return true; } else { return false; } } public function setEnd($isEnd) { $this->isEnd = $isEnd; } public function getEnd() { return $this->isEnd; } } /** * 模拟阻塞的协程1 * */ function taskObject1() { $timer = new timer(1,function($value,timer $timer) { if($value >= 5) { $timer->setEnd(true); } echo '<br>'.'A '.$value; }); $tid = (yield getTaskId()); while (true) { if($timer->getEnd() == true) { break; } yield $timer->run(); } } /** * 模拟阻塞的协程2 * */ function taskObject2() { $timer = new timer(2,function($value,timer $timer) { if($value >= 3) { $timer->setEnd(true); } echo '<br>'.'B '.$value; }); $tid = (yield getTaskId()); while (true) { if($timer->getEnd() == true) { break; } yield $timer->run(); } } $scheduler = new Scheduler; $scheduler->newTask(taskObject1()); $scheduler->newTask(taskObject2()); $scheduler->run();
L'implémentation ci-dessus est :
Générer deux tâches, les exécuter en parallèle et attribuer à chaque tâche un Simulez quelques secondes de blocage pendant l'exécution ;
permet une commutation en douceur lorsque les coroutines sont commutées, et le blocage des tâches ne s'affecte pas
Réflexion :
dans l'une des tâches, la tâche de blocage empêchera en fait le changement de coroutine. le principe de mise en œuvre de la coroutine Il en va de même pour les livres. sleep()
, c'est-à-dire si je veux vraiment atteindre le non-. le blocage ou l'implémentation asynchrone doivent dépendre du langage sous-jacent. sleep()
Ce qui suit est un exemple de découpe d'un programme en morceaux aussi petits que possible pour l'exécution :
// 一个简单的例子 <?php function xrange($start, $end, $step = 1) { for ($i = $start; $i <= $end; $i += $step) { yield $i; } } foreach (xrange(1, 1000000) as $num) { echo $num, "\n"; }Cet exemple consiste à convertir la plage d'utilisation d'origine pour générer un grand tableau d'entiers en exécution fragmentée, ce qui signifie que la valeur spécifiée est obtenue lors du parcours. Du point de vue du code, la consommation de mémoire est très faible par rapport à avant.
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!