Python的asyncio(协程)
本文转载自:https://pythonav.com/wiki/detail/6/91/ 1.协程 协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行。例如: 1 2 3 4 5 6 7 8 9 10 11 12 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才能使用。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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关键字实现协程代码。 1 2 3 4 5 6 7 8 9 10 11 12 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关键字是在Python3.3中引入的。 1.3 asyncio 在Python3.4之前官方未提供协程的类库,一般大家都是使用greenlet等其他来实现。在Python3.4发布后官方正式支持协程,即:asyncio模块。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 关键字在Python3.5版本中正式引入,基于他编写的协程代码其实就是 上一示例 的加强版,让代码可以更加简便。 Python3.8之后 @asyncio.coroutine 装饰器就会被移除,推荐使用async & awit 关键字实现协程代码。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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 中均已支持。 接下来,我们也会针对 asyncio模块 + async & await 关键字进行更加详细的讲解。 ...