swoole 协程介绍
协程的执行顺序:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
go(function () {    echo "hello go1 \n";});echo "hello main \n";go(function () {    echo "hello go2 \n";}); | 
go() 是 \Co::create() 的缩写,用来创建一个协程,接受callback作为参数,callback中的代码。会在这个新建的协程中执行。
备注:\Swoole\Coroutine 可以简写为 \Co
上面的代码执行结果:
| 
 1 
2 
3 
4 
 | 
# php co.phphello go1hello mainhello go2 | 
实际执行过程:
- 运行此段代码,系统启动一个新进程
 - 遇到 go() ,当前进程中生成一个协程,协程中输出 hello go1,协程退出
 - 进程继续向下执行代码,输出 hello main
 - 再生成一个协程,协程中输出 hello go2,协程退出
 
下面稍微改一下执行顺序
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
 | 
use Co;go(function () {    Co::sleep(1); // 只新增了一行代码    echo "hello go1 \n";});echo "hello main \n";go(function () {    echo "hello go2 \n";}); | 
\Co::sleep() 函数功能和 sleep() 差不多,但是它模拟的是IO等待,执行的顺序如下:
| 
 1 
2 
3 
4 
 | 
# php co.phphello mainhello go2hello go1 | 
上面的实际执行过程如下:
- 运行此段代码,系统启动一个进程
 - 遇到 go(),当前进程中生成一个协程
 - 协程中遇到IO阻塞(这里是 Co::sleep() 模拟出来的IO等待),协程让出控制,进入协程调度队列
 - 进程继续向下执行,输出 hello main
 - 执行下一个协程,输出 hello go2
 - 之前的协程准备就绪,继续执行,输出 hello go1
 
协程快在哪?减少IO阻塞导致的性能损失
一般的计算机任务分为两种:
- CPU密集型,比如加减乘除等科学计算
 - IO密集型,比如网络请求,文件读写等
 
高性能相关的两个概念:
- 并行:同一个时刻,同一个CPU只能执行同一个任务,要同时执行多个任务,就需要有多个CPU才行
 - 并发:由于CPU切换任务非常快,所以让人感觉像是有多个任务同时执行
 
协程适合的场景是IO密集型应用,因为协程在IO阻塞时会自动调度,减少IO阻塞导致的时间损失。
普通版:执行4个任务
| 
 1 
2 
3 
4 
5 
6 
 | 
$n = 4;for ($i = 0; $i < $n; $i++) {    sleep(1);    echo microtime(true) . ": hello $i \n";};echo "hello main \n"; | 
执行结果:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
# php co.php1528965075.4608: hello 01528965076.461: hello 11528965077.4613: hello 21528965078.4616: hello 3hello mainreal    0m 4.02suser    0m 0.01ssys     0m 0.00s | 
单个协程版:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
 | 
$n = 4;go(function () use ($n) {    for ($i = 0; $i < $n; $i++) {        Co::sleep(1);        echo microtime(true) . ": hello $i \n";    };});echo "hello main \n"; | 
执行结果:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
# php co.phphello main1528965150.4834: hello 01528965151.4846: hello 11528965152.4859: hello 21528965153.4872: hello 3real    0m 4.03suser    0m 0.00ssys     0m 0.02s | 
多协程版本:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
 | 
$n = 4;for ($i = 0; $i < $n; $i++) {    go(function () use ($i) {        Co::sleep(1);        echo microtime(true) . ": hello $i \n";    });};echo "hello main \n"; | 
执行结果:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
# php co.phphello main1528965245.5491: hello 01528965245.5498: hello 31528965245.5502: hello 21528965245.5506: hello 1real    0m 1.02suser    0m 0.01ssys     0m 0.00s | 
这三种版本为什么时间上有很大的差异?
- 普通版本:会遇到IO阻塞,导致的性能损失
 - 单协程版本:尽管IO阻塞引发了协程调度,但当前只有一个协程,调度之后还是执行当前协程
 - 多协程版本:真正发挥出协程的优势,遇到IO阻塞时发生调度,IO就绪时恢复运行
 
下面将多协程版本修改为CPU密集型
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
$n = 4;for ($i = 0; $i < $n; $i++) {    go(function () use ($i) {        // Co::sleep(1);        sleep(1);        echo microtime(true) . ": hello $i \n";    });};echo "hello main \n"; | 
执行的结果:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
# php co.php1528965743.4327: hello 01528965744.4331: hello 11528965745.4337: hello 21528965746.4342: hello 3hello mainreal    0m 4.02suser    0m 0.01ssys     0m 0.00s | 
只是将 Co::sleep() 改成了sleep() ,时间又和普通版本差不多,原因是:
- sleep() 可以看做是CPU密集型任务,不会引起协程的调度
 - Co::sleep() 模拟的是IO密集型任务,会引发协程的调度
 
这就是为什么协程适合IO密集型应用。
下面使用一组对比,使用redis:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
 | 
// 同步版, redis使用时会有 IO 阻塞$cnt = 2000;for ($i = 0; $i < $cnt; $i++) {    $redis = new \Redis();    $redis->connect('redis');    $redis->auth('123');    $key = $redis->get('key');}// 单协程版: 只有一个协程, 并没有使用到协程调度减少 IO 阻塞go(function () use ($cnt) {    for ($i = 0; $i < $cnt; $i++) {        $redis = new Co\Redis();        $redis->connect('redis', 6379);        $redis->auth('123');        $redis->get('key');    }});// 多协程版, 真正使用到协程调度带来的 IO 阻塞时的调度for ($i = 0; $i < $cnt; $i++) {    go(function () {        $redis = new Co\Redis();        $redis->connect('redis', 6379);        $redis->auth('123');        $redis->get('key');    });} | 
性能对比:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
 | 
# 多协程版# php co.phpreal    0m 0.54suser    0m 0.04ssys     0m 0.23s# 同步版# php co.phpreal    0m 1.48suser    0m 0.17ssys     0m 0.57s | 
swoole协程和go协程对比:单进程 VS 多线程
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
 | 
package mainimport (    "fmt"    "time")func main() {    go func() {        fmt.Println("hello go")    }()    fmt.Println("hello main")    time.Sleep(time.Second)} | 
执行结果:
| 
 1 
2 
3 
 | 
$ go run test.gohello mainhello go | 
go代码的执行过程如下:
- 运行 go 代码,系统启动一个新进程
 - 查找 package main ,然后执行其中的 func main()
 - 遇到协程,交给协程调度器执行
 - 继续向下执行,输出 hello main
 - 如果不添加 time.Sleep(time.Second),main函数执行完,程序结束,进程退出,导致调度中的协程也终止
 
swoole和go实现协程调度的模型不同,go中使用的是MPG模型:
- M 指的是 Machine, 一个M直接关联了一个内核线程
 - P 指的是 processor, 代表了M所需的上下文环境, 也是处理用户级代码逻辑的处理器
 - G 指的是 Goroutine, 其实本质上也是一种轻量级的线程
 

而swoole中的协程调度使用单进程模型,所有协程都是在当前进程中进行调度,单进程的好处是:简单 / 不用加锁 / 性能高。
swoole 协程介绍的更多相关文章
- [转]Unity3D协程介绍 以及 使用
		
作者ChevyRay ,2013年9月28日,snaker7译 原文地址:http://unitypatterns.com/introduction-to-coroutines/ 在Unity中,协 ...
 - [Sw] Swoole-4.2.9 可以尝试愉快应用 Swoole 协程
		
大家知道 Swoole 提供了方便于服务器.网络编程的模式,简化了多进程编程. 这直接让 PHP 的运行很容易变成常驻内存的 Server 程序,执行效率上有了数倍的提升. 但是这一切还没有让人足够兴 ...
 - python 全栈开发,Day43(引子,协程介绍,Greenlet模块,Gevent模块,Gevent之同步与异步)
		
昨日内容回顾 I/O模型,面试会问到I/O操作,不占用CPU.它内部有一个专门的处理I/O模块.print和写log 属于I/O操作,它不占用CPU 线程GIL保证一个进程中的多个线程在同一时刻只有一 ...
 - {python之协程}一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二
		
python之协程 阅读目录 一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二 一 引子 本 ...
 - Unity3D协程介绍 以及 使用
		
作者ChevyRay ,2013年9月28日,snaker7译 原文地址:http://unitypatterns.com/introduction-to-coroutines/ 在Unity中,协 ...
 - 【python】-- 协程介绍及基本示例、协程遇到IO操作自动切换、协程(gevent)并发爬网页
		
协程介绍及基本示例 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他 ...
 - Swoole 协程 MySQL 客户端与异步回调 MySQL 客户端的对比
		
Swoole 协程 MySql 客户端与 异步回调 MySql 客户端的对比 为什么要对比这两种不同模式的客户端? 异步 MySQL 回调客户端是虽然在 Swoole 1.8.6 版本就已经发布了, ...
 - Swoole 协程与 Go 协程的区别
		
Swoole 协程与 Go 协程的区别 进程.线程.协程的概念 进程是什么? 进程就是应用程序的启动实例. 例如:打开一个软件,就是开启了一个进程. 进程拥有代码和打开的文件资源,数据资源,独立的内存 ...
 - Swoole协程与传统fpm同步模式比较
		
如果说数组是 PHP 的精髓,数组玩得不6的,根本不能算是会用PHP.那协程对于 Swoole 也是同理,不理解协程去用 Swoole,那就是在瞎用. 首先,Swoole 只能运行在命令行(Cli)模 ...
 
随机推荐
- 【漫话DevOps】What is DevOps?
			
最近几年"DevOps"这个关键词经常出现在项目开发当中,特别是随着微服务/容器/cloud在项目中的大范围应用,你不想知道都很难.作为一个伴随CI/CD到DevOps一路走来的工 ...
 - 你必须要知道的babel二三事
			
1. 什么是babel 本文基于的babel版本是7.11.6,本文所有示例github Babel is a toolchain that is mainly used to convert ECM ...
 - selenium中各个模块操作:下拉框、鼠标悬浮连贯、拼图拖拽操作、以及其他拖拽操作、连线操作
			
1.下拉框的修改操作 方法一:定位到元素后,通过select选择对应的值 方法二:通过两次点击的方法:没有select的value属性时,采用click两次的方法去选择: click第一次后,出现下拉 ...
 - ajax之---原生ajax
			
原生ajax,基于XMLHttpRequest对象来完成请求 <!DOCTYPE html><html><head lang="en"> ...
 - Cloudera Manager和CDH安装部署
			
本次安装采用离线安装的方式,需要提前下载好需要的包. 1. 准备工作 1.1 环境说明 操作系统:RedHat企业级Linux6.5 64-bit Cloudera Manager:5.8.4 CDH ...
 - 深度神经网络conda环境下载
			
介绍 因为使用conda下载数据有时候因为网络问题下载非常慢,因此我把conda的环境备份好,到时可以直接使用conda的conda create -n 新环境名字 –clone 环境的路径 , 直接 ...
 - Book of Shaders 02 - 矩阵:二维仿射变换练习
			
0x00 一些废话 如果要深入学习 CG (Computer Graphics,计算机图形学),必然要学习相关的数学知识.CG 涉及到多个不同的领域,根据所研究领域的不同,也会涉及到不同的数学分支.但 ...
 - 1.3Hadoop版本说明
 - linux学习(三)Linux 系统目录结构
			
一.查看目录 登录系统后,在当前命令窗口下输入命令: ls / 树状目录结构: 二.目录解析 /bin: 存放二进制可执行文件(ls,cat,mkdir等). /boot: 存放启动Linux时使用的 ...
 - 吴恩达-机器学习+udacity从机器学习到深度学习