协程的嵌套,意思就是在一个协程中await另外一个协程。要实现这个目标,我们要将协程封装成Task, 因为其他代码可以直接await这个Task。
下面代码嵌套关系是: main协程嵌套evaluate_work协程,evaluate_work协程嵌套do_some_work协程。启动事件循环后,先执行main, 进入for loop, 然后 await evaluate_work(task)会执行evaluate_work协程(不明白协程如何执行,请参考我的另一篇博客,之协程执行)。
import time
import asyncio
now = lambda: time.time()
async def do_some_work(x):
print("do_some_work: ", x)
return "some_work is done for {}".format(x)
async def evaluate_work(task):
print('evaluation: starting...')
result = await task
print("work evaluation returned: ", result)
async def main():
for i in range(5):
work_coroutine = do_some_work(i)
# task = loop.create_task(work_coroutine )
task = asyncio.ensure_future(work_coroutine)
await evaluate_work(task)
start = now()
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(main())
loop.close()
end = now()
print("total run time:", end - start)
程序是这样执行得:启动事件循环,执行main函数,main函数里进入for loop。创建一个work_coroutine, 并封装为task。task作为参数传入evaluate_work里, 并执行这个evaluate_work协程对象。进入evaluate_work, 先打印print(‘evaluation: starting…’),又遇到 await task( 这里的task 参数是传入得work_coroutine协程)于是执行do_some_work,进入do_some_work, 先打印print("do_some_work: “, x),然后返回"some_work is done for {}”.format(x)。紧接着回到evaluate_work中,把返回得结果赋值给result, 接着打印print("work evaluation returned: ", result)。如此重复for loop, 直到执行完为止。
evaluation: starting...
do_some_work: 0
work evaluation returned: some_work is done for 0
evaluation: starting...
do_some_work: 1
work evaluation returned: some_work is done for 1
evaluation: starting...
do_some_work: 2
work evaluation returned: some_work is done for 2
evaluation: starting...
do_some_work: 3
work evaluation returned: some_work is done for 3
evaluation: starting...
do_some_work: 4
work evaluation returned: some_work is done for 4
total run time: 0.0027039051055908203
在main函数里,再加一个asyncio.gather 或者 asyncio.wait方法,都可以再次收集协程return的结果。
import time
import asyncio
now = lambda: time.time()
async def do_some_work(x):
print("do_some_work: ", x)
return "some_work is done for {}".format(x)
async def evaluate_work(task):
print('evaluation: starting...')
result = await task
print("work evaluation returned: ", result)
async def main():
tasks = []
for i in range(5):
work_coroutine = do_some_work(i)
task = asyncio.ensure_future(work_coroutine)
tasks.append(task)
# task = loop.create_task(coroutine)
await evaluate_work(task)
# dones, pendings = await asyncio.wait(tasks)
# for task in dones:
# print("task result:", task.result())
results = await asyncio.gather(*tasks)
for result in results:
print("Task result:", result)
start = now()
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(main())
loop.close()
end = now()
print("total run time:", end - start)
evaluation: starting...
do_some_work: 0
work evaluation returned: some_work is done for 0
evaluation: starting...
do_some_work: 1
work evaluation returned: some_work is done for 1
evaluation: starting...
do_some_work: 2
work evaluation returned: some_work is done for 2
evaluation: starting...
do_some_work: 3
work evaluation returned: some_work is done for 3
evaluation: starting...
do_some_work: 4
work evaluation returned: some_work is done for 4
Task result: some_work is done for 0
Task result: some_work is done for 1
Task result: some_work is done for 2
Task result: some_work is done for 3
Task result: some_work is done for 4
total run time: 0.0023107528686523438