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

PHP下的异步尝试2:认识协程

时间:2023-03-29 15:39:54 PHP

PHP下的异步尝试系列如果你对PHP中的generator不是很了解,可以参考以下目录阅读PHP下的异步尝试1:认识GeneratorPHPPHP下的异步尝试2:Coroutine下的异步尝试3PHP:PHP版Coroutinethunkify自动执行器PHP异步尝试4:PHP中的Promise【PHP下的异步尝试5:PromiseinPHP版继续完善】多任务(并行和并发)前说了协程,就说说多进程、多线程、并行和并发。对于单核处理器,多进程多任务的原理是让操作系统每次给一个任务分配一定的CPU时间片,然后中断,让下一个任务执行一定的时间片,然后中断继续执行下一个,如此反复。因为切换和执行任务的速度非常快,给外部用户的印象就是多个任务的执行是同时进行的。多进程的调度是由操作系统来实现的,进程本身无法控制什么时候被调度。控制被传递回调度程序,以便其他任务可以继续运行。这与抢占式多任务处理完全相反,在抢占式多任务处理中,调度程序可以强制中断正在运行的任务,无论它是否愿意。如果程序仅依靠自动移交控制,一些恶意程序很容易占用所有CPU时间而不与其他任务共享。协程的调度是通过协程自身主动让出控制权给外层调度器来实现的。回到刚才生成器实现xrange函数的例子,整个执行过程的交替可以用下图来表示:协程可以理解为一个纯User态的线程,通过协作而不是抢占来进行任务切换。与进程或线程相比,协程的所有操作都可以在用户态而不是操作系统内核态完成,创建和切换的消耗非常低。简单的说协程就是提供一个方法中断当前任务的执行,保存当前局部变量,恢复当前局部变量下次继续执行。我们可以将一个大任务拆分成多个小任务依次执行。如果有小任务正在等待系统IO,则跳过它,执行下一个小任务。这种往复调度实现了IO操作和CPU计算的并行。执行一般会提高任务的执行效率,这就是协程的意义。单核下,多线程必须并发;但是目前统一进程的多线程可以在多核CPU下运行。所以可以并行。并发性是指处理多个同时发生的活动的能力,并发事件不一定必须同时发生。并行(Parallesim)是指同时发生的两个并发事件,具有并发的意思,但并发不一定是并行的。可以在重叠的时间段内执行多个操作。并行和并发的区别并发是指程序的结构。并行度是指程序运行时的状态。并行性必须是并发的。并行是一种并发设计。在生成器的基础上,增加了向生成器返回数据的功能(调用者向被调用的生成器函数发送数据)。这就把生成器到调用者的单向通信变成了两者之间的双向通信。我们在上一篇文章中已经讲过send方法。让我们了解协程的同步代码。在异步执行代码之前,我们的代码就像这样functionprintNum($max,$caller){for($i=0;$i<$max;$i++){echo"Scheduler:"。$来电者。“打印:”。$我。PHP_EOL;}}printNum(3,"caller1");printNum(3,"caller2");#输出dispatcher:caller1print:0dispatcher:caller1print:1dispatcher:caller1print:2dispatcher:caller2print:0dispatcher:caller2print:1dispatcher:caller2print:2use协程后改进代码初稿,手动调整generator的执行#这段代码手动调整流程执行代码的顺序,当然这段代码也可以不用协程,就用这个过程来说明协程的作用吧#生成器给了我们Interrupt函数,协程[generatorsend]给了我们重新唤醒生成器函数的能力functionprintNumWithGen($max){for($i=0;$i<$max;$i++){$res=yield$i;回声$res;}}$gen1=printNumWithGen(3);$gen2=printNumWithGen(3);//手动执行caller1,然后caller2$gen1->send("Scheduler:caller1print:".$gen1->current().PHP_EOL);$gen2->send("Scheduler:caller2print:".$gen2->current().PHP_EOL);//手动执行caller1和caller2$gen1->send("Scheduler:caller1prints:".$gen1->current().PHP_EOL);$gen2->send("Scheduler:caller2prints:".$gen2->current().PHP_EOL);//手动执行caller2再执行caller1$gen2->send("Scheduler:caller2print:".$gen2->current().PHP_EOL);$gen1->send("Scheduler:caller1print:".$gen1->current().PHP_EOL);#输出scheduler:caller1print:0scheduler:caller2print:0scheduler:caller1print:1scheduler:caller2print:1scheduler:caller2print:2scheduler:caller1print:2总结上面的案例应该让大家明白了协程设计的意义以及协程的使用方法,那么我们会自动为我们的协程创建一个自动调度器(Coautomaticexecutor),没有需要手动中断和恢复