This article describes the method of php implementing asynchronous based on coroutines. Share it for your reference, as follows:
Most of the coroutines in php on github are implemented based on this article:/2012/12/22/。
Their final result is to turn the callback into code that executes gracefully in sequence, but it is still blocking, not really asynchronous.
For example, the most popular:/recoilphp/recoil
Install first:
composer require recoil/recoil
implement:
<?php // include __DIR__ . '/vendor/'; use Recoil\React\ReactKernel; $i = 100000; ReactKernel::start(task1()); ReactKernel::start(task2()); function task1(){ global $i; echo "wait start" . PHP_EOL; while ($i-- > 0) { yield; } echo "wait end" . PHP_EOL; }; function task2(){ echo "Hello " . PHP_EOL; yield; echo "world!" . PHP_EOL; }
result:
wait start
//Wait for several seconds
wait end
Hello
world!
I originally wanted to make the two tasks parallel, but the two tasks became serial, and I couldn't do anything during the waiting time. React responsive programming strictly prohibits this kind of waiting, so I wrote a php version by referring to the unity3d coroutine. On code:
<?php // //The timer relies on swoole implementation, and other methods can also be used to implement the timerclass Coroutine { //The timer interval can be changed as needed, unit ms const TICK_INTERVAL = 1; private $routineList; private $tickId = -1; public function __construct() { $this->routineList = []; } public function start(Generator $routine) { $task = new Task($routine); $this->routineList[] = $task; $this->startTick(); } public function stop(Generator $routine) { foreach ($this->routineList as $k => $task) { if($task->getRoutine() == $routine){ unset($this->routineList[$k]); } } } private function startTick() { swoole_timer_tick(self::TICK_INTERVAL, function($timerId){ $this->tickId = $timerId; $this->run(); }); } private function stopTick() { if($this->tickId >= 0) { swoole_timer_clear($this->tickId); } } private function run() { if(empty($this->routineList)){ $this->stopTick(); return; } foreach ($this->routineList as $k => $task) { $task->run(); if($task->isFinished()){ unset($this->routineList[$k]); } } } } class Task { protected $stack; protected $routine; public function __construct(Generator $routine) { $this->routine = $routine; $this->stack = new SplStack(); } /** * [run coroutine schedule] * @return [type] [description] */ public function run() { $routine = &$this->routine; try { if(!$routine){ return; } $value = $routine->current(); //Nested coroutine if ($value instanceof Generator) { $this->stack->push($routine); $routine = $value; return; } //Nested coroutine returns if(!$routine->valid() && !$this->stack->isEmpty()) { $routine = $this->stack->pop(); } $routine->next(); } catch (Exception $e) { if ($this->stack->isEmpty()) { /* throw the exception */ return; } } } /** * [isFinished determines whether the task is completed] * @return boolean [description] */ public function isFinished() { return $this->stack->isEmpty() && !$this->routine->valid(); } public function getRoutine() { return $this->routine; } }
Test code:
<?php // require ''; $i = 10000; $c = new Coroutine(); $c->start(task1()); $c->start(task2()); function task1(){ global $i; echo "wait start" . PHP_EOL; while ($i-- > 0) { yield; } echo "wait end" . PHP_EOL; }; function task2(){ echo "Hello " . PHP_EOL; yield; echo "world!" . PHP_EOL; }
result:
wait start
Hello
world!
//Wait for a few seconds, but don't block
wait end
For more information about PHP related content, please check out the topic of this site:PHP extension development tutorial》、《Summary of PHP network programming skills》、《Summary of the usage of php curl》、《Complete collection of PHP array (Array) operation techniques》、《PHP data structure and algorithm tutorial》、《Summary of PHP Programming Algorithm"and"Summary of usage of php strings》
I hope this article will be helpful to everyone's PHP programming.