使用协程处理多任务
协程是语言专门为并发操作设计的一个结构。一个协程函数当被调用时创建了一个协程对象,调用者可以使用协程的send()方法运行协程函数的代码。协程可以使用await关键字暂停当前执行将控制权交给其他协程,当协程被暂停,它的运行状态被保存下来,可以在下一次被唤醒时继续执行。
启动协程
通过asyncio事件循环有几种不同的方式可以启动协程,最简单的方法是使用run_until_complete()函数,直接传入一个协程。(注意:run_until_complete()函数传入的是一个Future对象,如果传入的是一个协程,协程会被ensure_future()函数自动包装成Future对象,返回Future的结果或者抛出异常)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import asyncio async def coroutine(): print('in coroutine') event_loop = asyncio.get_event_loop() try: print('starting coroutine') coro = coroutine() print('entering event loop') event_loop.run_until_complete(coro) finally: print('closing event loop') event_loop.close()
|
第一步是获取一个事件循环对象,可以使用默认的事件循环类型,也可以使用特定的事件循环,在这个例子中使用了默认的事件循环类型。run_until_complete()函数传入协程对象启动了循环,在协程运行结束后停止了事件循环。
1 2 3 4 5 6
| $ python3 asyncio_coroutine.py starting coroutine entering event loop in coroutine closing event loop
|
协程返回值
协程的返回值需要等待协程运行完成才能接受。
1 2 3 4 5 6 7 8 9 10 11 12
| import asyncio async def coroutine(): print('in coroutine') return 'result' event_loop = asyncio.get_event_loop() try: return_value = event_loop.run_until_complete(coroutine()) print('it returned: {!r}'.format(return_value)) finally: event_loop.close()
|
在这种情况下,run_until_complete()函数会等待协程运行完成并返回协程的运行结果。
1 2 3 4
| $ python3 asyncio_coroutine_return.py in coroutine it returned: 'result'
|
协程链
一个协程可以启动其他的协程并等待返回结果,这使得将任务分解为可重用的部分变得更加容易。下面的例子有两个阶段,必须按顺序执行,但是可以与其他操作并行运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import asyncio async def outer(): print('in outer') print('waiting for result1') result1 = await phase1() print('waiting for result2') result2 = await phase2(result1) return (result1, result2) async def phase1(): print('in phase1') return 'result1' async def phase2(arg): print('in phase2') return 'result2 derived from {}'.format(arg) event_loop = asyncio.get_event_loop() try: return_value = event_loop.run_until_complete(outer()) print('return value: {!r}'.format(return_value)) finally: event_loop.close()
|
await关键字用来将新的协程任务发送到事件循环。
1 2 3 4 5 6 7 8
| $ python3 asyncio_coroutine_chain.py in outer waiting for result1 in phase1 waiting for result2 in phase2 return value: ('result1', 'result2 derived from result1')
|
生成器替代协程
协程函数是asyncio框架设计中的一个关键组件,它们提供了一种语言结构,用于停止执行程序的一部分,保留该调用的状态,并在以后的时间重新进入状态,这些都是并发性框架的重要功能。
Python 3.5引入了新的语言特性,使用async def来定义原生的协程,使用await来交出控制权,上面关于asyncio的例子也充分的体现了这些新的特性。早期版本的Python 3可以使用被asyncio.coroutine()装饰的生成器函数和yield from达到同样的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import asyncio @asyncio.coroutine def outer(): print('in outer') print('waiting for result1') result1 = yield from phase1() print('waiting for result2') result2 = yield from phase2(result1) return (result1, result2) @asyncio.coroutine def phase1(): print('in phase1') return 'result1' @asyncio.coroutine def phase2(arg): print('in phase2') return 'result2 derived from {}'.format(arg) event_loop = asyncio.get_event_loop() try: return_value = event_loop.run_until_complete(outer()) print('return value: {!r}'.format(return_value)) finally: event_loop.close()
|
上面的例子使用生成器函数替代了原生的协程。
1 2 3 4 5 6 7 8
| $ python3 asyncio_generator.py in outer waiting for result1 in phase1 waiting for result2 in phase2 return value: ('result1', 'result2 derived from result1')
|
本文翻译自《The Python3 Standard Library By Example》asyncio相关章节