当前位置: 首页 > 后端技术 > PHP

PHP协程

时间:2023-03-29 20:33:41 PHP

协程“协程”是用户态的一个线程。要理解什么是“用户态线程”,首先要理解什么是“内核态线程”。内核模式线程由操作系统调度。切换线程上下文时,必须先保存上一个线程的上下文,然后再执行下一个线程。当条件满足时,切换回上一个线程并恢复上下文。协程也是一样,只是用户态的线程不是由操作系统调度的,而是由程序员调度的,在用户态——从关于“用户态线程”的链接描述来看,我们用一个小例子来加深我们的理解。我们有两个函数task1和task2。我们手动安排一下它们的执行顺序,比如在task1执行到一半的时候执行task2,交替执行两个或多个函数(这就是协程的概念。)。让我们有一个正常的函数调用方法:current();$task2->current();上面的输出:task1functionexecution1task2functionexecution1很好,上面的结果达到了我们的预期。但是如何让函数中的代码执行下来呢?调用generator的next方法:$task1->next();$task2->next();最后,你将看到的输出是两个函数交替执行的输出:task1函数执行1task2函数执行1task1函数执行2task2函数执行2小段总结上面的代码实现可以抽象出任务和调度两个概念。Task就是任务函数,调度就是我们调用这些任务函数的方式。任务和调度,我们简单封装了一个任务生成器和调度器//任务生成器$createTask=(function(){$tasks=[];returnfunction($callback)use(&$tasks){$task=['task'=>$callback(),'id'=>count($tasks)+1,];array_push($tasks,$task);return$task;};})();//调度函数schedule($tasks){$first=[];while(!empty($tasks)){$task=array_shift($tasks);如果(!array_key_exists($task['id'],$first)){$first[$task['id']]=true;$任务['任务']->当前();}else{$task['task']->next();}if(!$task['task']->valid()){unset($tasks[$k]);}else{array_push($tasks,$task);}}}使用$tasks=[$createTask(function(){echo"任务1第一次执行\n";yield;echo"任务1第二次执行\n";}),$createTask(function(){echo"任务2执行第一次\n";yield;echo"任务2执行第二次\n";})];schedule($tasks);输出结果:任务1执行第一次任务2执行第一个任务1执行第二次执行任务2从结果可以看出调度器已经实现了多个任务之间的协同Web请求现在有需求!即当任务遇到网络请求时,我们不需要等待网络请求的响应结果。而是当遇到网络请求时,我们暂停任务,然后执行其他任务,然后在网络请求收到响应结果时通知。我们在处理这个的时候,需要用到非阻塞IO调用相关的技术,这涉及到系统内核层面。如果您想了解更多,可以点击链接进行描述。在PHP中,我们需要安装一个扩展的eio。可以自己安装peclinstalleio代码:$tasks=[$createTask(function(){echo"第一次执行任务1\n";yield;echo"第二次执行任务1\n";}),$createTask(function(){echo"任务2第一次执行\n";eio_custom(function(){returnfile_get_contents('https://segmentfault.com/');},EIO_PRI_DEFAULT,function($data,$ret){echo"请求完成\n";});yield;echo"任务2第二次执行\n";})];schedule($tasks);eio_event_loop();第一次执行任务2时,遇到网络请求时,我们将请求任务交给系统内核,然后切换到其他任务,请求任务完成后回调我们传入的函数。输出结果:Task1执行第一个任务2执行第一个任务1执行第二个任务2执行第二个任务2执行第一个请求完成!