gpt4 book ai didi

python - asyncio.wait 是否仅在调用所有 done_callbacks 后返回?

转载 作者:行者123 更新时间:2023-11-28 22:44:10 24 4
gpt4 key购买 nike

想象一下下面的代码:

import asyncio

loop = asyncio.get_event_loop()

@asyncio.coroutine
def coro():
yield from asyncio.sleep(1)

def done_callback(future):
print("Callback called")

@asyncio.coroutine
def run():
future = asyncio.async(coro(), loop=loop)
future.add_done_callback(done_callback)
yield from asyncio.wait([future])
print("Wait returned")

loop.run_until_complete(run())

输出是:

$ python3 /tmp/d.py 
Callback called
Wait returned

因此 done_callbackwait 返回之前被调用。

这是有保证的行为吗?我没有在文档中找到任何关于此的内容。

wait返回后调用done_callback是否可能出现这种情况?

最佳答案

与当前 asyncio执行,只要add_done_callbackcoro 的事件循环迭代之前被调用实际上完成了,所有的回调都是用 add_done_callback 安排的将在 wait 之前执行解锁。原因是 asyncio.wait内部调用 add_done_callback在所有Future你传递给它的实例,所以它只是 Task 的回调链中的另一个回调.当你的 Task完成,asyncio电话 set_result在上面,它看起来像这样:

def set_result(self, result):
"""Mark the future done and set its result.

If the future is already done when this method is called, raises
InvalidStateError.
"""
if self._state != _PENDING:
raise InvalidStateError('{}: {!r}'.format(self._state, self))
self._result = result
self._state = _FINISHED
self._schedule_callbacks()

_schedule_callbacks看起来像这样:

def _schedule_callbacks(self): 
"""Internal: Ask the event loop to call all callbacks.

The callbacks are scheduled to be called as soon as possible. Also
clears the callback list.
"""
callbacks = self._callbacks[:]
if not callbacks:
return

self._callbacks[:] = []
for callback in callbacks:
self._loop.call_soon(callback, self)

所以,一旦 Task完成了,loop.call_soon用于安排所有回调(包括您的 done_callback 函数,以及由 asyncio.wait 添加的回调)。

事件循环将在一次迭代中处理内部回调列表中的所有回调,这意味着 asyncio.wait回调和你的 done_callback将在单个事件循环迭代中一起执行:

    # This is the only place where callbacks are actually *called*.
# All other places just add them to ready.
# Note: We run all currently scheduled callbacks, but not any
# callbacks scheduled by callbacks run this time around --
# they will be run the next time (after another I/O poll).
# Use an idiom that is thread-safe without using locks.
ntodo = len(self._ready)
for i in range(ntodo):
handle = self._ready.popleft()
if handle._cancelled:
continue
if self._debug:
t0 = self.time()
handle._run()

所以,只要你的add_done_callback在事件循环迭代之前运行,其中 coro完成后,您可以保证(至少通过当前的实现)它将在 asyncio.wait 之前运行解锁。但是,如果 add_done_callbackcoro 之后执行完成或在与 coro 相同的事件循环迭代中完成,直到 asyncio.wait 之后才会运行完成。

我会说如果add_done_callbackasyncio.wait 之前调用,就像在您的示例中一样,您可以确信它将始终在 wait 之前运行解锁,因为你的回调将在 asyncio.wait 之前回调链中的回调。如果你最终调用 add_done_callback 之后 asyncio.wait已经开始,它现在仍然可以工作,但理论上实现可能会以一种不会发生的方式改变;例如,它可以更改为在每个事件循环迭代中仅处理有限数量的回调。我怀疑是否会做出改变,但这是可能的。

关于python - asyncio.wait 是否仅在调用所有 done_callbacks 后返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29883518/

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