PHP下的异步尝试系列

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

  1. PHP下的异步尝试一:初识生成器
  2. PHP下的异步尝试二:初识协程
  3. PHP下的异步尝试三:协程的PHP版thunkify自动执行器
  4. PHP下的异步尝试四:PHP版的Promise
  5. [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://segmentfault.com/a/1190000016472108

PHP下的异步尝试二:初识协程的更多相关文章

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

    PHP下的异步尝试系列 如果你还不太了解PHP下的生成器和协程,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunk ...

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

    PHP下的异步尝试系列 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunkify自动执行器 PHP下的异步尝试四:PHP版的Promise ...

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

    PHP下的异步尝试系列 如果你还不太了解PHP下的生成器和协程,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunk ...

  4. Kotlin Coroutine(协程): 二、初识协程

    @ 目录 前言 一.初识协程 1.runBlocking: 阻塞协程 2.launch: 创建协程 3.Job 4.coroutineScope 5.协程取消 6.协程超时 7.async 并行任务 ...

  5. 异步等待的 Python 协程

    现在 Python 已经支持用协程进行异步处理.但最近有建议称添加协程以全面完善 Python 的语言结构,而不是像现在这样把他们作为生成器的一个类型.此外,两个新的关键字---异步(async)和等 ...

  6. 异步时代-java的协程路在何方

    面试官:你知道协程吗? 你:订机票的那个吗,我常用. 面试官:行,你先回去吧,到时候电话联系 ........ 很尴尬,但是事实是,很大一部分的程序员不知道协程是啥玩意,更大一部分的程序员,项目中没用 ...

  7. Py修行路 python基础 (十二) 协程函数应用 列表生成式 生成器表达式

    一.知识点整理: 1.可迭代的:对象下有_iter_方法的都是可迭代的对象 迭代器:对象._iter_()得到的结果就是迭代器 迭代器的特性: 迭代器._next_() 取下一个值 优点: 1.提供了 ...

  8. Swoole 中使用 TCP 异步服务器、TCP 协程服务器、TCP 同步客户端、TCP 协程客户端

    TCP 异步风格服务器 异步风格服务器通过监听事件的方式来编写程序.当对应的事件发生时底层会主动回调指定的函数. 由于默认开启协程化,在回调函数内部会自动创建协程,遇到 IO 会产生协程调度,异步风格 ...

  9. python进阶(二) 多进程+协程

    我们大多数的时候使用多线程,以及多进程,但是python中由于GIL全局解释器锁的原因,python的多线程并没有真的实现 实际上,python在执行多线程的时候,是通过GIL锁,进行上下文切换线程执 ...

随机推荐

  1. 2019-03-28 SQL Server char/nchar/nvarchar

    带n 的是用于处理unicode 字符,即处理中英文的字符 一般来说,如果含有中文字符,用nchar/nvarchar,如果纯英文和数字,用char/varchar char 定长 char(10), ...

  2. yii 表单小部件使用

    首先创建model层 因为要使用表单小部件 所以要加载相应的组件 这里需要的组件有 yii\widgets\ActiveForm 和 yii\helpers\Html 接下来在model定义的clas ...

  3. python处理时间戳

    代码如下: def timestamp_datetime(value):     format = '%Y-%m-%d %H:%M:%S'     # value为传入的值为时间戳(整形),如:133 ...

  4. navicate11不能激活的问题

    navicate11不能激活的问题 学习了:http://blog.csdn.net/sanbingyutuoniao123/article/details/52589678 不要安装在系统盘,如果安 ...

  5. 12. mysql show status

    状态名 作用域 详解 Aborted_clients Global 因为client没有正确关闭连接导致client终止而中断的连接数 Aborted_connects Global 试图连接到MyS ...

  6. MAME 0.201 发布,重温童年的街机模拟器

    MAME 0.201 已发布,MAME 最初是街机模拟器,随着时间的推移,MAME 吸收了姊妹项目 MESS(多机种模拟器超级系统),所以 MAME 现在还记录了各种各样的(大多是老式的)电脑游戏.掌 ...

  7. 这里是指推送通知跟NSNotification有区别:

    1.NSNotification是系统内部发出通知,一般用于内部事件的监听,或者状态的改变等等,是不可见的2.本地通知与远程通知是可见的,主要用于告知用户或者发送一些App的内容更新,推送一些相关的消 ...

  8. hdoj--3062--party(2-sat 可行解)

    Party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  9. Java做一个时间的程序,为什么要除以1000*60*60*24啊。这个数字是什么意思啊。

    1000耗秒(1秒),60秒(1分),60分(1小时),24小时(1天)

  10. 3.linux(ubuntu)常用服务器搭建

    1 ftp 1.1 ftp服务器 1.安装vsftpd服务器 sudo apt-get install vsftpd 2.配置vsftpd.conf文件 sudo vi /etc/vsftpd.con ...