[求教] 协程与 IO 多路复用区别?

2020-07-17 13:35:36 +08:00
 kaiser1992
网上搜索 python asyncio 包的介绍,清一色都涉及到了 IO 多路复用( EventLoop ),非阻塞确实能够提升性能,但是和协程有啥关系呢~?

我的疑惑是 python 的原生协程是基于生成器增强来实现的,怎么与 IO 多路复用关联到一块呢?
4420 次点击
所在节点    Python
14 条回复
reus
2020-07-17 14:29:54 +08:00
建议不要理会也不要使用“多路复用”、“非阻塞”、“协程”这些词,因为不同人会有不同的理解,而且没法达成一致。
ruanimal
2020-07-17 14:34:49 +08:00
协程只是让 eventloop 写起来更方便,不然你得写回调。

eventloop 必须非阻塞的 fd 加多路复用
chevalier
2020-07-17 14:39:46 +08:00
都学过操作系统,操作系统的功能之一就是提供硬件的访问接口,例如:网络 IO

协程是“用户态”的概念,IO 多路复用是系统调用的接口,是“用户态”与“内核态”交互的方式;毕竟协程是无法直接访问网卡缓冲区的,需要调用系统接口来获取网络 IO 的数据。

所以网络程序,协程一般需要搭配 IO 多路复用才能发挥最大威力,协程提升并发处理的能力,网络 IO 能力就要靠 IO 多路复用。

说得比较简单,细说了能写好几篇文章了。建议看看 tornado/asyncio 的源码,网络通信模块,或者自己用 C 写一写 epoll 系统调用,就容易理解了。
coldmonkeybit
2020-07-17 15:07:02 +08:00
借楼请教,没用过 Python,请问 python 中的协程跟 go 的协程类似么?
kaiser1992
2020-07-17 18:34:54 +08:00
@chevalier 所以说,如果我的程序一点没有 IO,协程执行过程中就不会用到多路复用的机制了吧~?
palfortime
2020-07-17 20:02:33 +08:00
协程和 io 多路复用是两个维度的东西,协程只要有 io 就可以派上用途,线程也可以搭配 io 多路复用。
guochao
2020-07-17 22:53:35 +08:00
> 如果我的程序一点没有 IO,协程执行过程中就不会用到多路复用的机制了吧~?

对,如果一个程序没有 IO 和其他暂停线程的手段,也就是说是《计算密集型》的程序,那么就和多路复用无关,毕竟这是个 IO 概念。

协程的本质是利用多路复用和信号尽可能多的《在同一个线程上跑更多的任务》,IO 和休眠的时候协程就会暂停,遇到信号就会唤醒。无非就是把以前的回调换了一种形式,让回调变成顺序的过程,更适合人类理解。

《 IO 密集型》的程序利用协程可以获取《更高的并发度(同一个线程上可以跑更多的 IO 任务)》,但是也会带来《更高的延迟(唤醒和调度的开销)》。计算密集型的程序几乎不会有任何提升。
dongcidaci
2020-07-18 06:22:51 +08:00
斗胆说一下,协程就是用户态的线程,上下文切换开销小。多路复用是一种 IO 方式。貌似没什么关系。
ysc3839
2020-07-18 10:10:38 +08:00
推荐看一下这篇文章 https://blog.panicsoftware.com/coroutines-introduction/

我个人的理解,无栈协程是一种可以中途返回,后面再从之前返回的地方恢复执行的函数。利用这种特性可以实现许多功能,比如生成器,求出一个值之后返回,需要下一个值的时候再恢复执行。或者用来编写异步 IO 代码,在开始 IO 操作后返回,IO 操作完成之后恢复执行。
而异步 IO 又有多种实现方式。可以用最简单的多线程来实现,协程启动一个新线程来进行阻塞 IO 操作,同时返回,新线程中的 IO 操作完成后,在新线程中恢复执行协程。
也可以用单线程来实现,但是要配合 IO 多路复用来实现,IO 多路复用简单说是同时监视多个文件描述符是否就绪,协程在当前线程进行非阻塞的 IO 操作之后返回,然后当前线程会检测文件描述符是否就绪,就绪后恢复执行协程。
ysc3839
2020-07-18 10:15:56 +08:00
总结起来是,协程跟 IO 多路复用关系不大,因为完全可以用协程写一个不涉及 IO 操作的代码,即使涉及到了 IO 操作,也可以使用多线程的模型。
Python 的 asyncio 选择了单线程+IO 多路复用的模型,所以相关资料都会涉及,但是 asyncio 并不等同于协程。
irosyking
2020-07-20 17:28:03 +08:00
1 、Async IO Framework = eventloop + non-blocking sockets + coroutines
Async IO Framework = eventloop + non-blocking sockets + callbacks

2 、Coroutine = Future + Task + Generator
Lazy computation = Generator
Marinej
2020-07-21 10:02:11 +08:00
协程就是单线程的调度,有了 IO 多路复用,epoll 这种技术,协程在 IO 密集型任务上才能发光发热,没有 IO 多路复用,协程也是白给
ychost
2020-07-27 16:03:58 +08:00
IO 复用 是系统层面的词语(操作系统级别支持,epoll 之类的),协程是软件层面的支持,比如 go 语言支持协程,kotlin 的协议是通过一个线程去轮询轻量的任务实现的,所以无法锁协程,只能锁协程外面的那根线程
fasionchan
2020-11-03 13:50:10 +08:00
简单说,IO 多路复用是高效的底层功能,但非阻塞的编程模型回调函数满天飞,并不直观。而协程是对 IO 多路复用的抽象封装,让你可以用阻塞的编程模型编写非阻塞的代码,解决回调满天飞的弊端。

我基于 epoll 实现了一个极简的协程库,仅仅只有 100 多行代码,有需要可以参考下:

https://mp.weixin.qq.com/s/MaLMf3HZCYfmzxOY1QfPnw

麻雀虽小,五脏俱全。关于 IO 多路复用与协程的关系,以及协程的实现原理,一下子就清晰了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/690868

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX