资讯专栏INFORMATION COLUMN

PHP下的异步尝试二:初识协程

MudOnTire / 566人阅读

摘要:如果仅依靠程序自动交出控制的话,那么一些恶意程序将会很容易占用全部时间而不与其他任务共享。多个操作可以在重叠的时间段内进行。

PHP下的异步尝试系列

如果你还不太了解PHP下的生成器,你可以根据下面目录翻阅

PHP下的异步尝试一:初识生成器

PHP下的异步尝试二:初识协程

PHP下的异步尝试三:协程的PHP版thunkify自动执行器

PHP下的异步尝试四:PHP版的Promise

[PHP下的异步尝试五:PHP版的Promise的继续完善]

多任务 (并行和并发)

在讲协程之前,先谈谈多进程、多线程、并行和并发。

对于单核处理器,多进程实现多任务的原理是让操作系统给一个任务每次分配一定的 CPU 时间片,然后中断、让下一个任务执行一定的时间片接着再中断并继续执行下一个,如此反复。

由于切换执行任务的速度非常快,给外部用户的感受就是多个任务的执行是同时进行的。

多进程的调度是由操作系统来实现的,进程自身不能控制自己何时被调度,也就是说: 进程的调度是由外层调度器抢占式实现的

而协程要求当前正在运行的任务自动把控制权回传给调度器,这样就可以继续运行其他任务。这与抢占式的多任务正好相反, 抢占多任务的调度器可以强制中断正在运行的任务, 不管它自己有没有意愿。如果仅依靠程序自动交出控制的话,那么一些恶意程序将会很容易占用全部 CPU 时间而不与其他任务共享。

协程的调度是由协程自身主动让出控制权到外层调度器实现的

回到刚才生成器实现 xrange 函数的例子,整个执行过程的交替可以用下图来表示:

协程可以理解为纯用户态的线程,通过协作而不是抢占来进行任务切换。

相对于进程或者线程,协程所有的操作都可以在用户态而非操作系统内核态完成,创建和切换的消耗非常低。

简单的说协程 就是提供一种方法来中断当前任务的执行,保存当前的局部变量,下次再过来又可以恢复当前局部变量继续执行。

我们可以把大任务拆分成多个小任务轮流执行,如果有某个小任务在等待系统 IO,就跳过它,执行下一个小任务,这样往复调度,实现了 IO 操作和 CPU 计算的并行执行,总体上就提升了任务的执行效率,这也便是协程的意义

多线程
在单核下,多线程必定是并发的;
不过现在的统一进程的多线程是可以运行在多核CPU下,所以可以是并行的

并发(Concurrency)

是指能处理多个同时性活动的能力,并发事件之间不一定要同一时刻发生。

并行(Parallesim)

是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行。
多个操作可以在重叠的时间段内进行。

并行和并发区别

并发指的是程序的结构,并行指的是程序运行时的状态
并行一定是并发的,并行并发设计的一种
单线程永远无法达到并行状态

协程

协程的支持是在生成器的基础上, 增加了可以回送数据给生成器的功能(调用者发送数据给被调用的生成器函数).
这就把生成器到调用者的单向通信转变为两者之间的双向通信.
我们在上篇文章已经讲过了send方法, 下面让我们理解下协程

同步代码

在没有涉及到异步执行代码之前,我们的代码都是这样的

function printNum($max, $caller)
{
    for ($i=0; $i<$max; $i++ ) {
        echo "调度者:" . $caller . "  打印:" . $i . PHP_EOL;
    }
}

printNum(3, "caller1");
printNum(3, "caller2");

# output
调度者:caller1  打印:0
调度者:caller1  打印:1
调度者:caller1  打印:2
调度者:caller2  打印:0
调度者:caller2  打印:1
调度者:caller2  打印:2
使用协程后改进的代码

初稿,手动调整生成器执行

# 本代码手动调整了进程执行代码的顺序,当然本代码实现不用协程也可以,只是利用本流程说明协程作用
# 生成器给了我们函数中断,协程[生成器send]给了我们重新唤起生成器函数的能力
function printNumWithGen($max)
{
    for ($i=0; $i<$max; $i++ ) {
        $res = yield $i;
        echo $res;
    }
}

$gen1 = printNumWithGen(3);
$gen2 = printNumWithGen(3);

// 手动执行caller1 再 caller2
$gen1->send("调度者: caller1 打印:" . $gen1->current() . PHP_EOL);
$gen2->send("调度者: caller2 打印:" . $gen2->current() . PHP_EOL);

// 手动执行caller1 再 caller2
$gen1->send("调度者: caller1 打印:" . $gen1->current() . PHP_EOL);
$gen2->send("调度者: caller2 打印:" . $gen2->current() . PHP_EOL);

// 手动执行caller2 再 caller1
$gen2->send("调度者: caller2 打印:" . $gen2->current() . PHP_EOL);
$gen1->send("调度者: caller1 打印:" . $gen1->current() . PHP_EOL);

# output
调度者: caller1 打印:0
调度者: caller2 打印:0
调度者: caller1 打印:1
调度者: caller2 打印:1
调度者: caller2 打印:2
调度者: caller1 打印:2
总结
上面案例应该让大家理解了协程设计的意义和如何使用协程

那么接下去我们为我们的协程自动一个自动调度器(Co自动执行器),无需再手动来中断和恢复了

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29418.html

相关文章

  • PHP下的异步尝试四:PHP版的Promise

    摘要:结果打印我结论或问题这里我们基础实现了一个可以用于生产环境的后续我们会接续完善这个的特有方法,比如等后续再介绍用实现的自动执行器等附录参考中文对象入门阮一峰 PHP下的异步尝试系列 如果你还不太了解PHP下的生成器和协程,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunkify自动执行器 PHP下的...

    lentoo 评论0 收藏0
  • PHP下的异步尝试三:协程PHP版thunkify自动执行器

    摘要:函数并不是生成器协程函数自动执行的唯一方案。因为自动执行的关键是,必须有一种机制,自动控制生成器协程函数的流程,接收和交还程序的执行权。回调函数可以做到这一点,对象也可以做到这一点。本系列的下一篇,将介绍基于的实现的自动执行器。 PHP下的异步尝试系列 如果你还不太了解PHP下的生成器和协程,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 P...

    wudengzan 评论0 收藏0
  • PHP下的异步尝试一:初识生成器

    摘要:下的异步尝试系列下的异步尝试一初识生成器下的异步尝试二初识协程下的异步尝试三协程的版自动执行器下的异步尝试四版的下的异步尝试五版的的继续完善生成器类获取迭代器当前值获取迭代器当前值返回当前产生的键生成器从上一次处继续执行重置迭代器向生成器中 PHP下的异步尝试系列 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunkify自...

    tomorrowwu 评论0 收藏0
  • lua web快速开发指南(1) - 初识cf框架

    摘要:作者水果糖的小铺子是什么全称为一个基于事件驱动与协程的高性能网络框架目前主要面向开发内部主要实现了包括与协议的利用轻量级协程可以很轻松保持成千上万的长连接内置了丰富的开发库与常见的第三方协议目前在快速开发业务原型上有不可比拟的优势的代码与封 作者: 水果糖的小铺子(CandyMi) cf是什么? cf全称为: CoreFramework. 一个基于Reactor事件驱动与协程的lua高...

    Cheng_Gang 评论0 收藏0
  • IMI 基于 Swoole 开发的协程 PHP 开发框架 常驻内存、协程异步非阻塞

    摘要:介绍是基于开发的协程开发框架,拥有常驻内存协程异步非阻塞等优点。宇润我在年开发并发布了第一个框架,一直维护使用至今,非常稳定,并且有文档。于是我走上了开发的不归路 showImg(https://segmentfault.com/img/bVbcxQH?w=340&h=160); 介绍 IMI 是基于 Swoole 开发的协程 PHP 开发框架,拥有常驻内存、协程异步非阻塞IO等优点。...

    airborne007 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<