详解php协程知识点


Posted in PHP onSeptember 21, 2018

多任务 (并行和并发)

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

对于单核处理器,多进程实现多任务的原理是让操作系统给一个任务每次分配一定的 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自动执行器),无需再手动来中断和恢复了

PHP 相关文章推荐
?繁体转换的class
Oct 09 PHP
php批量删除数据
Jan 18 PHP
php 网页游戏开发入门教程一(webgame+design)
Oct 26 PHP
ThinkPHP中的关联模型注意点
Jun 16 PHP
php面向对象中static静态属性和静态方法的调用
Feb 08 PHP
CodeIgniter表单验证方法实例详解
Mar 03 PHP
详解PHP的Yii框架的运行机制及其路由功能
Mar 17 PHP
Yii实现的多级联动下拉菜单
Jul 13 PHP
PHP面向对象五大原则之依赖倒置原则(DIP)详解
Apr 08 PHP
PHP convert_cyr_string()函数讲解
Feb 13 PHP
PHP实现提高SESSION响应速度的几种方法详解
Aug 09 PHP
Laravel配合jwt使用的方法实例
Oct 25 PHP
在php的yii2框架中整合hbase库的方法
Sep 20 #PHP
php实现在线考试系统【附源码】
Sep 18 #PHP
PHP htmlspecialchars() 函数实例代码及用法大全
Sep 18 #PHP
Laravel用户授权系统的使用方法示例
Sep 16 #PHP
Laravel中错误与异常处理的用法示例
Sep 16 #PHP
laravel获取不到session的三种解决办法【推荐】
Sep 16 #PHP
win7 wamp 64位 php环境开启curl服务遇到的问题及解决方法
Sep 16 #PHP
You might like
PHP5在Apache下的两种模式的安装
2006/09/05 PHP
php 小乘法表实现代码
2009/07/16 PHP
php通过获取头信息判断图片类型的方法
2015/06/26 PHP
thinkphp3.2同时连接两个数据库的简单方法
2019/08/13 PHP
浅析JavaScript中的类型和对象
2013/11/29 Javascript
Javascript中Array.prototype.map()详解
2014/10/22 Javascript
JavaScript中获取Radio被选中的值
2015/11/11 Javascript
jQuery ajax时间差导致的变量赋值问题分析
2016/01/22 Javascript
jQuery animate和CSS3相结合实现缓动追逐效果附源码下载
2016/04/18 Javascript
Wireshark基本介绍和学习TCP三次握手
2016/08/15 Javascript
详解Vue 实例中的生命周期钩子
2017/03/21 Javascript
React利用插件和不用插件实现双向绑定的方法详解
2017/07/03 Javascript
React Native第三方平台分享的实例(Android,IOS双平台)
2017/08/04 Javascript
通俗易懂地解释JS中的闭包
2017/10/23 Javascript
vue.js绑定事件监听器示例【基于v-on事件绑定】
2018/07/07 Javascript
angular6 填坑之sdk的方法
2018/12/27 Javascript
浅析VUE防抖与节流
2020/11/24 Vue.js
[01:06:19]DOTA2-DPC中国联赛定级赛 LBZS vs SAG BO3第二场 1月8日
2021/03/11 DOTA
解读Python中degrees()方法的使用
2015/05/18 Python
python爬虫系列Selenium定向爬取虎扑篮球图片详解
2017/11/15 Python
Python解决pip install时出现的Could not fetch URL问题
2019/08/01 Python
Python 实例方法、类方法、静态方法的区别与作用
2019/08/14 Python
Python列表元素常见操作简单示例
2019/10/25 Python
Python爬取网页信息的示例
2020/09/24 Python
python录音并调用百度语音识别接口的示例
2020/12/01 Python
anaconda升级sklearn版本的实现方法
2021/02/22 Python
使用phonegap操作数据库的实现方法
2017/03/31 HTML / CSS
Vans澳大利亚官网:购买鞋子、服装及配件
2019/09/05 全球购物
给排水专业应届生求职信
2013/10/12 职场文书
自我评价范文分享
2014/01/04 职场文书
标准离婚协议书(2014版)
2014/10/05 职场文书
检讨书怎么写
2015/01/23 职场文书
家长会主持词开场白
2015/05/29 职场文书
永不妥协观后感
2015/06/10 职场文书
Mysql中where与on的区别及何时使用详析
2021/08/04 MySQL
交互式可视化js库gojs使用介绍及技巧
2022/02/18 Javascript