这一章节“协程”话题的讨论是为了让我们对之后协程风格服务端有更全面的了解。所以我们需要先一起了解一下什么是协程?协程有什么作用?

当大家第一次看到“协程”这个词的时候,应该都一样会打开某度、某歌搜索一翻,然后搜到一堆很玄幻的概念,比如以下这一句:“协程(coroutine)也是一种程序组件。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。”往往让人看了一脸问号-_-

其实“协程”这东西,我们可以这么理解,进程是个容器,对应具体干活的是线程;同样的道理,我们可以把线程看成是一个容器,协程是线程中具体干活的过程。换种说法,可以把协程想象成一个个函数(每个函数的作用不一样),而协程就是在同一个时间段内让这些函数同时工作。

协程最主要的作用是:让原来要使用异步+回调方式写的非人类代码,可以用看似同步的方式写出来(即:按串行模型去组织原本分散在不同上下文中的代码逻辑)。

网上有一些观点,说协程可以很好解决IO瓶颈问题(因为这时线程发挥不了作用)。编者只想说, IO 是系统调用,这个 IO 不是用户态能处理的,协程 是没办法绕开的,所以最终还是给堵了。如果 协程 真的能处理堵塞问题,那么很多经典的 Unix 网络编程书籍里面应该有 多协程 模式才对。

编者作为IT界的泥石流,习惯了异步的写法,对于协程抱着接受但是审视的态度。今天我们就一起看看swoole下的协编程。

我们先看看一段简易的协程代码:

echo "main start",PHP_EOL;
Co\run(function(){
echo "co 1 start",PHP_EOL; go(function(){
echo "co 2 start",PHP_EOL;echo "co 2 end",PHP_EOL;
}); go(function(){
echo "co 3 start",PHP_EOL;echo "co 3 end",PHP_EOL;
}); echo "co 1 end",PHP_EOL;
});
echo "end";

这段代码的执行结果是:

main  start

co 1 start

co 2 start

co 2 end

co 3 start

co 3 end

co 1 end

end

好像也没什么嘛,就是代码顺序执行的结果。先不要急,我们一起看看代码中比较陌生的部分:

Co\run():在Swoole直接裸写协程启动,就需要调用这个函数(其实是对 Swoole\Coroutine\Scheduler 类 (协程调度器类) 的封装),可以理解为C语言里的main()函数。(另外,Swoole 提供的 2 个进程管理模块 Process 和 Process\Pool 的 start 方法,此种启动方式会在进程启动的时候创建协程容器,参考这两个模块构造函数的 enable_coroutine 参数)。

go():添加一个子协程。

现在,我们把代码修改如下(添加了Co::sleep)

echo "main start",PHP_EOL;
Co\run(function(){
echo "co 1 start",PHP_EOL; go(function(){
echo "co 2 start",PHP_EOL;
co::sleep(1);
echo "co 2 end",PHP_EOL;
}); go(function(){
echo "co 3 start",PHP_EOL;
co::sleep(.5);
echo "co 3 end",PHP_EOL;
}); echo "co 1 end",PHP_EOL;
});
echo "end";

这时的结果会变成:

main start

co 1 start

co 2 start

co 3 start

co 1 end

co 3 end

co 2 end

end

是不是很神奇:)根据等待的时间,协程会自动调度现在可以马上就处理的代码片断。嗯,这就是协程最大的优势。

我们再做一个实验,把上面的co::sleep()函数换成php自带的sleep()函数会发生什么事?

echo "main start",PHP_EOL;
Co\run(function(){
echo "co 1 start",PHP_EOL; go(function(){
echo "co 2 start",PHP_EOL;
sleep(1); //注意这里
echo "co 2 end",PHP_EOL;
}); go(function(){
echo "co 3 start",PHP_EOL;
sleep(3); //注意这里
echo "co 3 end",PHP_EOL;
}); echo "co 1 end",PHP_EOL;
});
echo "end";

这时,我们得到的结果同样会是:

main  start

co 1 start

co 2 start

co 2 end

co 3 start

co 3 end

co 1 end

end

区别在于在co 2 start和co 3 start会被阻塞等待。究其原因就是在co::sleep()内部会用yield把时间片让出来,而sleep()则是在系统层面等待。这就是说为什么系统IO是协程绕不开的原因,该等的还是得等,只不过用了一些技巧是在其它地方等而已。

这就给了我们一些启发,如果用协程编程,碰到需要阻塞的部分(比如sleep、http请求、mysql连接、文件读写),需要用swoole为我们提供的现在协程库;如果协程库不够用,则利用异步原理与协程库实现自己的协程组件。

但是,swoole已经考虑到程序员中不乏杠精,就想把上面这请阻塞操作变成协程,只需如下操作就可以实现把代码“一键协程化”:

Swoole\Runtime::enableCoroutine();    //重点在这一句
echo "main start",PHP_EOL;
Co\run(function(){
echo "co 1 start",PHP_EOL; go(function(){
echo "co 2 start",PHP_EOL;
sleep(2);
echo "co 2 end",PHP_EOL;
}); go(function(){
echo "co 3 start",PHP_EOL;
sleep(1);
echo "co 3 end",PHP_EOL;
}); echo "co 1 end",PHP_EOL;
});
echo "end";

虽然swoole提供了“一键协程化”的神仙操作,可以把文件操作,sleep,Mysqli,PDO,streams等都变成异步IO,但是要注意,底层是使用了HOOK的方式把原PHP的代码调用转移到了swoole的函数内,可参考这里。所以认识swoole提供的原生协程库也是非常重要的。

要注意的是:Swoole\Runtime::enableCoroutine(),并不针对curl。如果想要把curl也协程化,需要调用Swoole\Runtime::enableCoroutine($flags = SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL); 对于Co::set(['hook_flags' => SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL]); 也是一样。

接下来,再来一段代码:

echo "main start",PHP_EOL;
echo "co 1 start",PHP_EOL; go(function(){
echo "co 2 start",PHP_EOL;
co::sleep(1);
echo "co 2 end",PHP_EOL;
}); go(function(){
echo "co 3 start",PHP_EOL;
co::sleep(.5);
echo "co 3 end",PHP_EOL;
}); echo "co 1 end",PHP_EOL; echo "end",PHP_EOL;

我们得到的结果是:

main start

co 1 start

co 2 start

co 3 start

co 1 end

end

co 2 end

co 2 end

在这一段代码中,没有协程容器Co\run()的存在,go()子协程同样会被调用。可以看出协程容器可以保证容器内的协程代码全部执行完成后,再跳出容器往下执行外部的代码。

好了,协程初探就先到这里了。接下去,我们会先了解协程版本的TCP服务器。关于swoole协程的其它话题,我们后续会进行讨论。

---------------------------  我是可爱的分割线  ----------------------------

最后博主借地宣传一下,漳州编程小组招新了,这是一个面向漳州青少年信息学/软件设计的学习小组,有意向的同学点击链接,联系我吧。

Swoole从入门到入土(8)——协程初探的更多相关文章

  1. 数据结构和算法(Golang实现)(6)简单入门Golang-并发、协程和信道

    并发.协程和信道 Golang语言提供了go关键字,以及名为chan的数据类型,以及一些标准库的并发锁等,我们将会简单介绍一下并发的一些概念,然后学习这些Golang特征知识. 一.并发介绍 我们写程 ...

  2. Generator(生成器),入门初基,Coroutine(原生协程),登峰造极,Python3.10并发异步编程async底层实现

    普遍意义上讲,生成器是一种特殊的迭代器,它可以在执行过程中暂停并在恢复执行时保留它的状态.而协程,则可以让一个函数在执行过程中暂停并在恢复执行时保留它的状态,在Python3.10中,原生协程的实现手 ...

  3. python从入门到放弃之协程

    协程 协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B ...

  4. [Swoole系列入门教程 5] UDP协议和demo

    • 客户端服务端没有任何联系 • 指定地址跟端口,不关心消息是否发送成功 • 心跳检测不能影响到客户端• udp建立长连接

  5. [Sw] Swoole-4.2.9 可以尝试愉快应用 Swoole 协程

    大家知道 Swoole 提供了方便于服务器.网络编程的模式,简化了多进程编程. 这直接让 PHP 的运行很容易变成常驻内存的 Server 程序,执行效率上有了数倍的提升. 但是这一切还没有让人足够兴 ...

  6. Golang 入门 : goroutine(协程)

    在操作系统中,执行体是个抽象的概念.与之对应的实体有进程.线程以及协程(coroutine).协程也叫轻量级的线程,与传统的进程和线程相比,协程的最大特点是 "轻"!可以轻松创建上 ...

  7. swoole使用协程

    协程:协程可以理解为纯用户态的线程,其通过协作而不是抢占来进行切换.相对于进程或者线程,协程所有的操作都可以在用户态完成,创建和切换的消耗更低.Swoole可以为每一个请求创建对应的协程,根据IO的状 ...

  8. 协程与Swoole的原理,相关应用以及适用场景等

    什么是协程 协程(Coroutine)也叫用户态线程,其通过协作而不是抢占来进行切换.相对于进程或者线程,协程所有的操作都可以在用户态完成,创建和切换的消耗更低.协程是进程的补充,或者是互补关系. 要 ...

  9. [Swoole入门到进阶] [公开课] Swoole协程-Swoole4.4.4 提供 WaitGroup 功能

    在 Swoole4 中可以使用 channel 实现协程间的通信.依赖管理.协程同步. 简单来说,WaitGroup 就是使用 channel 的机制,让主协程等待所有子协程结束后才退出的功能. Co ...

  10. swoole| swoole 协程初体验 转

    swoole| swoole 协程初体验   date: 2018-5-30 14:31:38title: swoole| swoole 协程初体验description: 通过协程的执行初窥 swo ...

随机推荐

  1. TCP连接状态的多种判断方法

    ​ 前言 在TCP网络编程模型中,无论是客户端还是服务端,在网络编程的过程中都需要判断连接的对方网络状态是否正常.在linux系统中,有很多种方式可以判断连接的对方网络是否已经断开. 通过错误码和信号 ...

  2. Nginx arm编译安装

    Nginx arm编译安装 背景 计划编译一套产品. 能够比较方便快捷的进行 nginx的交付. 主要思想是源码编译 不仅能够在arm上面运行 也可以在x86上面编译 考虑性能还有一些扩展性. 高效处 ...

  3. [转帖]Linux系统NVME盘分区和挂载

    https://www.jianshu.com/p/04327f1b97cb 查看系统里面识别到的硬盘和分区的信息 $ sudo fdisk -l Disk /dev/nvme1n1: 1.8 TiB ...

  4. [转帖]Linux中的Page cache和Buffer cache详解

    1.内存情况 在讲解Linux内存管理时已经提到,当你在Linux下频繁存取文件后,即使系统上没有运行许多程序,也会占用大量的物理内存.这是因为当你读写文件的时候,Linux内核为了提高读写的性能和速 ...

  5. Walrus 0.5发布:重构交互流程,打造开箱即用的部署体验

    开源应用管理平台 Walrus 0.5 已于近日正式发布! Walrus 0.4 引入了全新应用模型,极大程度减少了重复的配置工作,并为研发团队屏蔽了云原生及基础设施的复杂度.Walrus 0.5 在 ...

  6. NLP文本匹配任务Text Matching [无监督训练]:SimCSE、ESimCSE、DiffCSE 项目实践

    NLP文本匹配任务Text Matching [无监督训练]:SimCSE.ESimCSE.DiffCSE 项目实践 文本匹配多用于计算两个文本之间的相似度,该示例会基于 ESimCSE 实现一个无监 ...

  7. VLE基于预训练文本和图像编码器的图像-文本多模态理解模型:支持视觉问答、图文匹配、图片分类、常识推理等

    VLE基于预训练文本和图像编码器的图像-文本多模态理解模型:支持视觉问答.图文匹配.图片分类.常识推理等 多模态预训练模型通过在多种模态的大规模数据上的预训练,可以综合利用来自不同模态的信息,执行各种 ...

  8. MySQL【一】基本使用----超详细教学

    相关文章: win10下MySQL安装教程(MySql-8.0.26超级详细)_丨汀.的博客-CSDN博客 1.RDBMS(Relational Databases Management System ...

  9. 【6】VScode 无法在终端输入问题,提示:无法在只读编辑器中编辑

    相关文章: [1]VScode中文界面方法-------超简单教程 [2]VScode搭建python和tensorflow环境 [3]VSCode 主题设置推荐,自定义配色方案,修改注释高亮颜色 [ ...

  10. 【7】vscode不同的窗口样式和颜色插件peacock、设置打开多个窗口、md文件打开方式和预览以及插入目录

    相关文章: [1]VScode中文界面方法-------超简单教程 [2]VScode搭建python和tensorflow环境 [3]VSCode 主题设置推荐,自定义配色方案,修改注释高亮颜色 [ ...