在如图所示的代码中,没有理由使用明确的future和
add_done_callback
,你可以随时
await
. 一个更现实的用例是如果情况发生逆转,如果
bar()
foo()
并需要访问其结果:
def bar():
fut = asyncio.create_task(foo())
def when_finished(_fut):
print("foo returned", fut.result())
fut.add_done_callback(when_finished)
如果这让你想起了“回叫地狱”,那么你就走上了正确的道路-
Future.add_done_callback
大致相当于
then
预异步/等待JavaScript承诺的运算符(细节不同是因为
then()
是一个返回另一个承诺的组合符,但基本思想是相同的。)
asyncio的很大一部分是
实施
like this
.
即使在处理非协程回调时,也很少有好的解决方案
原因
使用
添加\u完成\u回调
,而不是惯性或复制粘贴。例如,上述函数可以简单地转换为使用
等待
:
def bar():
async def coro():
ret = await foo()
print("foo returned", ret)
asyncio.create_task(coro())
这比原文更具可读性,而且
很
更容易适应更复杂的等待场景。它是
similarly easy
将协程插入较低级别的asyncio管道。
那怎么办
是
Future
API和
添加\u完成\u回调
? 我可以想到几个:
为了说明第一点,考虑一下你会怎么做。
实施
函数
asyncio.gather()
. 它必须允许传递的协程/未来运行并等待
全部的
添加\u完成\u回调
全部的
没有等待他们的一系列未来。以忽略异常处理和各种功能的最基本形式,
gather()
async def gather(*awaitables):
loop = asyncio.get_event_loop()
futs = list(map(asyncio.ensure_future, awaitables))
remaining = len(futs)
finished = loop.create_future()
def fut_done(fut):
nonlocal remaining
remaining -= 1
if not remaining:
finished.set_result(None) # wake up
for fut in futs:
fut.add_done_callback(fut_done)
await finished
# all awaitables done, we can return the results
return tuple(f.result() for f in futs)
即使你从不使用
添加\u完成\u回调