定义一个协程
通过 async 关键字定义一个协程。
通过 await 关键字挂起一个协程或 future 对象。
调用协程返回一个协程对象。
把协程对象或 task 对象放入事件循环中执行。
import asyncioasync def f():await asyncio.sleep(5) # 挂起一个协程print('5秒后输出此句')cor = f()print(cor) # 输出:<coroutine object f at 0x01EDB720>loop = asyncio.get_event_loop()loop.run_until_complete(cor) # 把协程对象放入事件循环中执行。
task 对象
实际上,只是把 coroutine 对象包装一下,加了个状态,在加入事件循环之前是 pending,执行后是 finished 。
run_until_complete 的参数是 future 对象,当传入一个协程对象时会包装成 task 对象,而 Task 是 Future 的子类。
task = loop.create_task(cor)print(task) # <Task pending coro=<f() running at a.py:4>>loop.run_until_complete(task)print(task) # <Task finished coro=<f() done, defined at a.py:4> result=None>
task 绑定回调
回调函数的最后一个参数是一个 future 对象,就是之前创建的 task 对象,保存着协程的返回结果。
import asyncioasync def f():await asyncio.sleep(1)print('1秒后输出此句')return 520cor = f()task = asyncio.ensure_future(cor) # 把协程包装成 task 对象def callback(future):print(future.result()) # 520print(future is task) # Truetask.add_done_callback(callback) # 绑定回调loop = asyncio.get_event_loop()loop.run_until_complete(task) 传入 task 对象
异步
终于来到了异步,上面的例子都只有一个协程,当一个事件循环中有多个协程时,就能体现出异步的好处。
但是,有一个问题,不能直接把多个协程(或多个 task)一下子传入 rununtil_complete 。需要多个 task 包装成一个 task。
可以用 asyncio.gather(*_coros_or_futures)、asyncio.wait(futures) 来包装。
gather 返回一个future 对象,多变一,协程返回结果就保存在这个对象。
wait 返回 (done, pending),done 和 future 都是 future 对象,多变二。
import asyncioasync def f(x):await asyncio.sleep(x)print('{}秒后输出此句'.format(x))return xtasks = map(asyncio.ensure_future, [f(1), f(3), f(5)])loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.gather(*tasks))# loop.run_until_complete(asyncio.wait(tasks))loop.close()
gather 和 wait 函数返回的 future 除了可以传给 run_until_complete 外,还可以从这个 future 中获取多个协程的返回结果
获取协程返回值
import asyncioasync def f(x):await asyncio.sleep(x)print('{}秒后输出此句'.format(x))return xasync def main():tasks = map(asyncio.ensure_future, [f(1), f(3), f(5)])results = await asyncio.gather(*tasks) # 从返回的 future 中获取多个协程结果for r in results:print(r)loop = asyncio.get_event_loop()loop.run_until_complete(main())loop.close()
asyncio.wait 的做法:
dones, pendings = await asyncio.wait(tasks)for r in dones:print(r.result())
还有一种方法获取协程返回值:asyncio.as_completed(futures),前面的 asyncio.wait、asyncio.gather 是把所有任务搞在一起,所有任务完成时在一起返回,而 asyncio.as_completed 每完成一个任务就返回对应的协程的返回值。
as_completed 返回一个迭代器,里面的值是 future 实例,所以 for 循环里面 await future 。
for future in asyncio.as_completed(tasks):r = await futureprint(r)
还可以这样干,把 main 当作中间层,用来把最里层 f 的结果传递给最外层模块:
import asyncioasync def f(x):await asyncio.sleep(x)print('{}秒后输出此句'.format(x))return x # 返回协程结果async def main():tasks = map(asyncio.ensure_future, [f(1), f(3), f(5)])return await asyncio.gather(*tasks) # 返回多个协程返回值,也可用 asyncio.wait 干loop = asyncio.get_event_loop()results = loop.run_until_complete(main()) # 取得多个协程返回值for r in results:print(r)loop.close()
很奇怪 run_until_complete 的作用域层,不能出现 gather、wait、as_completed 方法获取协程返回值。
