gpt4 book ai didi

python-asyncio - future.add_done_callback() 的用例是什么?

转载 作者:行者123 更新时间:2023-12-05 00:11:22 63 4
gpt4 key购买 nike

我了解如何将回调方法添加到 future 并在 future 完成时调用它。但是,当您已经可以从协程内部调用函数时,为什么这会有所帮助?

回调版本:

def bar(future):
# do stuff using future.result()
...

async def foo(future):
await asyncio.sleep(3)
future.set_result(1)

loop = asyncio.get_event_loop()
future = loop.create_future()
future.add_done_callback(bar)
loop.run_until_complete(foo(future))

选择:
async def foo():
await asyncio.sleep(3)
bar(1)

loop = asyncio.get_event_loop()
loop.run_until_complete(foo())

第二个版本什么时候不可用/不合适?

最佳答案

在所示的代码中,没有理由使用明确的 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)

如果这让你想起了“回调 hell ”,那么你就在正确的轨道上 - Future.add_done_callback大致相当于 then预异步/等待 JavaScript promise 的运算符。 (细节有所不同,因为 then() 是一个返回另一个 promise 的组合子,但基本思想是相同的。)

asyncio 的很大一部分是 实现在这种风格中,使用编排异步 future 的非异步函数。传输和协议(protocol)的基本层感觉就像是 Twisted 的现代化版本,协程和流作为其上的单独层实现,是更高级别的糖。使用基本工具集编写的应用程序代码看起来 like this .

即使在使用非协程回调时,也很少有充分的理由使用 add_done_callback ,除了惯性或复制粘贴。例如,上面的函数可以简单地转换为使用 await :

def bar():
async def coro():
ret = await foo()
print("foo returned", ret)
asyncio.create_task(coro())

这比原始版本更具可读性,并且更容易适应更复杂的等待场景。是 similarly easy将协程插入到较低级别的 asyncio 管道中。

那么,当一个人需要使用 Future 时,有哪些用例? API 和 add_done_callback ?我能想到几个:
  • 写作 new combinators .
  • 将协程代码与以更传统的回调样式编写的代码连接起来,例如 thisthis .
  • 编写 Python/C 代码,其中 async def不容易获得。

  • 为了说明第一点,考虑如何实现像 asyncio.gather() 这样的函数。 .它必须允许传递的协程/ future 运行并等待它们全部完成。这里 add_done_callback是一个非常方便的工具,允许该功能从所有 future 中请求通知,而无需串联等待它们。 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)

    即使你从不使用 add_done_callback ,这是一个很好的工具来了解和了解您真正需要它的罕见情况。

    关于python-asyncio - future.add_done_callback() 的用例是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53701841/

    63 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com