持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情
背景
协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术
简而言之,其实就是通过一个线程实现代码块相互切换执行
def func1():
print(1)
...
print(2)
def func2():
print(3)
...
print(4)
func1()
func2()
复制代码
上述代码是普通的函数定义和执行,按流程分别执行两个函数中的代码,并先后会输出:1、2、3、4
但如果介入协程技术那么就可以实现函数见代码切换执行,最终输入:1、3、2、4
协程的实现
在Python中有多种方式可以实现协程
- greenlet,是一个第三方模块,用于实现协程代码(Gevent协程就是基于greenlet实现)
- yield,生成器,借助生成器的特点也可以实现协程代码
- asyncio,在Python3.4中引入的模块用于编写协程代码
- async & awiat,在Python3.5中引入的两个关键字,结合asyncio模块可以更方便的编写协程代码
1.1 greenlet
greentlet 是一个第三方模块,需要提前安装 pip3 install greenlet
才能使用
from greenlet import greenlet
def func1():
print(1) # 第1步:输出 1
gr2.switch() # 第3步:切换到 func2 函数
print(2) # 第6步:输出 2
gr2.switch() # 第7步:切换到 func2 函数,从上一次执行的位置继续向后执行
def func2():
print(3) # 第4步:输出 3
gr1.switch() # 第5步:切换到 func1 函数,从上一次执行的位置继续向后执行
print(4) # 第8步:输出 4
gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch() # 第1步:去执行 func1 函数
复制代码
注意:switch 中也可以传递参数用于在切换执行时相互传递值
1.2 yield
基于 Python 的生成器的 yield 和yield form关键字实现协程代码
def func1():
yield 1
yield from func2()
yield 2
def func2():
yield 3
yield 4
f1 = func1()
for item in f1:
print(item)
复制代码
注意:yield form 关键字是在 Python 3.3 中引入的
1.3 asyncio
在 Python 3.4 之前官方未提供协程的类库,一般大家都是使用 greenlet 等其他来实现
在 Python 3.4 发布后官方正式支持协程,即:asyncio模块
import asyncio
@asyncio.coroutine
def func1():
print(1)
yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
print(2)
@asyncio.coroutine
def func2():
print(3)
yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
print(4)
tasks = [
asyncio.ensure_future( func1() ),
asyncio.ensure_future( func2() )
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
复制代码
注意:基于asyncio模块实现的协程比之前的要更厉害,因为他的内部还集成了遇到IO耗时操作自动切花的功能。
1.4 async & awit
- async & awit 关键字在 Python 3.5 版本中正式引入,基于他编写的协程代码其实就是上一示例的加强版,让代码可以更加简便
- Python 3.8 之后
@asyncio.coroutine
装饰器就会被移除,推荐使用 async & awit 关键字实现协程代码
import asyncio
async def func1():
print(1)
await asyncio.sleep(2)
print(2)
async def func2():
print(3)
await asyncio.sleep(2)
print(4)
tasks = [
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2())
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
复制代码
1.5 小结
关于协程有多种实现方式,目前主流使用是 Python 官方推荐的 asyncio 模块和 async&await 关键字的方式,例如:在tonado、sanic、fastapi、django3 中均已支持