1、协程和线程的区别
线程
- 操作系统自动调度
- 线程间切换需要陷入内核(在内核态切换),线程上下文规模比协程重,切换线程更费时
协程
- 用户程序自主切换协程,不由操作系统调度
- 协程上下文比线程轻量,切换速度更快,并且不会陷入内核,开销更小。
- 上下文的轻量体现在哪?
- 线程上下文是标准的进程上下文,包含的信息比较多,比如:cpu相关寄存器、线程优先级、pid、打开文件、信号、目录等等
- 协程上下文应该只有:当前函数局部变量、函数运行的位置等少量信息
2、Python的两个协程库
2.1 gevent
- 特点
- 使用monkey patch(猴子补丁)替换了标准库,你以为调用的是标准库的方法,实际已经被替换成gevent的自己的方法,遇到的阻塞调用,会自动让出cpu
- 基于libev去做的事件循环
- TODO
- gevent库包含内容挺多,之后在去了解其使用和实现原理(2022.04.12)
2.2 asyncio
- 特点
- asyncio控制权在自己手上,需要自己显式让出cpu
- 使用要点
- 使用asyncio库的装饰器将函数标记为协程
- 将所以函数形成的数组放入事件循环
- 开启,就会自动执行事件循环
- 注意点
- asyncio是Python标准库,在Python 3.5版本,使用async/await关键字简化了 asyncio库的操作。
2.3 两个方法的区别
- gevent是自动挡,asyncio是手动挡
- gevent可以使用monkey patch去替换原生接口(sleep,io请求接口等),自动注册到eventloop。asyncio需要使用相关的异步io方法才行。
- 其实这样看来,asyncio貌似好一点,更清晰吧。
2.4 从两个方法看协程的特点
- 协程的切换,需要用户程序主动地让出cpu(gevent也是采用monkey patch加入了自己的逻辑去主动让出的)
- 在需要阻塞等待的地方,就需要让出cpu。需要等待的场景比如:
- 操作磁盘io
- 操作网络io
- 需要sleep方法
- 这些阻塞方法都不能使用原始的,必须是经过协程库去处理,这是协程能够在阻塞时自动切换的关键所在。
迭代器,生成器
- 生成器设计初衷不是用来实现协程,而是
- 1、提供函数挂起能力,减少回调函数的使用
- 2、减少内存的消耗,动态的生成数据
- 现在python社区有意分离生成器与协程的关系