详解php协程知识点
多任务 (并行和并发)
在讲协程之前,先谈谈多进程、多线程、并行和并发。
对于单核处理器,多进程实现多任务的原理是让操作系统给一个任务每次分配一定的 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自动执行器),无需再手动来中断和恢复了
- 深入剖析ASP.NET的编译原理之一:动态编译(Dynamical Compilation)
- 深入剖析ASP.NET的编译原理之一:动态编译(Dynamical Compilation)
- 域名quco.com近10万元被交易
- Silverlight本地化
- Nodejs学习笔记(五)--- Express安装入门与模版引擎ejs
- Silverlight本地化
- Silverlight 3 创建一个简单的Behavior
- Nodejs学习笔记(六)--- Node.js + Express 构建网站预备知识
- Silverlight 3.0 中的 Local Connection
- 学习Spark——那些让你精疲力尽的坑
- 学习Spark——那些让你精疲力尽的坑
- Silverlight 3.0 中的 WriteableBitmap
- WCF后续之旅(10): 通过WCF Extension实现以对象池的方式创建Service Instance
- Silverlight菜单控件 — CurveMenu
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- 猿蜕变16——一文搞懂Spring事务花式玩法
- 猿蜕变17——一文掌握SSM框架搭建姿势
- 猿蜕变18——一文掌控SSM玩耍方式
- 猿蜕变19——一文掌握代码自动生成
- 基于Java的俄罗斯方块游戏的设计与实现
- Docker中部署RabbitMQ并使用Python3.x操作全书(Python操作RabbitMQ看这一篇就够了)
- 【CPP】模板类线性表
- leetcode 剑指 Offer 32 - II. 从上到下打印二叉树 II
- Matlab系列之程序优化
- 基于BS架构微博系统
- 10分钟学会pillow图像处理16式
- 编译原理课程设计词法分析
- 30分钟学会XGBoost
- Linux页框分配器之内存碎片化整理
- 手把手教你实现"短信轰炸"