gpt4 book ai didi

python - 取消任务会取消任务正在等待的 future 。它是如何工作的?

转载 作者:太空宇宙 更新时间:2023-11-04 02:13:12 32 4
gpt4 key购买 nike

我有一个实现请求/回复事务的可等待对象。如果事务超时,将在放弃并引发异常之前重试几次。

现在假设它总是超时,因为这就是我遇到的问题。

当任务开始此操作然后被取消时,重试将继续。这不是我想要的。我想完全取消操作。

我准备了一个 MCVE 并注意到,当任务被取消时,任务正在等待的 future 会被取消。这很适合我,它可以作为解决方案的基础,但我不明白为什么那个 future 会被取消以及我是否可以依赖它。

import asyncio

RETRIES = 2
TIMEOUT = 1.0

class ClientRPC:
def __init__(self):
self._reply = None
self._retries = RETRIES

def __await__(self):
self.start()
return self._reply.__await__()

def start(self):
loop = asyncio.get_event_loop()
if self._reply is None:
self._reply = loop.create_future()
loop.call_later(TIMEOUT, self.handle_timeout)
# send a request
print("REQUEST")

def handle_timeout(self):
print("TIMEOUT")
print("future", repr(self._reply._state))
if self._retries > 0:
self._retries -= 1
self.start()
else:
self._reply.set_exception(RuntimeError("Timeout!"))

def handle_reply(self, reply):
# unused in this example
pass

async def client():
transaction = ClientRPC()
try:
reply = await transaction
except asyncio.CancelledError:
print("--CANCELLED--")

async def test():
loop = asyncio.get_event_loop()
task = loop.create_task(client())
await asyncio.sleep(1.5)
task.cancel()
await asyncio.sleep(3)

asyncio.run(test()) # python 3.7+

输出(省略回溯):

REQUESTTIMEOUTfuture 'PENDING'REQUEST--CANCELLED--TIMEOUTfuture 'CANCELLED'   <-- why?REQUESTTIMEOUTfuture 'CANCELLED'Exception in callback ClientRPC.handle_timeout()handle: asyncio.base_futures.InvalidStateError: invalid state

最佳答案

I prepared a MCVE and noticed, that a future that the task is waiting for gets cancelled when the task is cancelled. This suits me fine, it could be a base for a solution, but I do not understand why that future gets cancelled and if I can rely on it.

是的,如果任务等待 future ,则该 future 将被取消。那个 future 可能是另一个任务,所以取消将传播到等待的最底层的 future 。实现makes sure的,但文档没有明确说明。

我会继续依赖这种行为,原因有二:

  • 如果不严重破坏向后兼容性,此时不可能更改它。开发商已经拒绝smaller更改,因为它们会破坏现有代码。

  • 没有其他 方法来实现不会导致资源泄漏的方法。如果你要取消的任务正在等待 future ,除了取消它你会做什么?如果你只是让它在后台运行,你可能会永远保留它,因为 future 可能永远不会自行退出。如果仅通过将其从调度程序中删除(同样,不取消)来“修复”这个问题, future 将永远没有机会清理它获取的资源,这肯定会导致资源泄漏。

因此,依赖向下传播的取消是安全的,使用 asyncio.shield() 屏蔽的 future 除外,它是为 意味着 的 future 保留的保持在后台运行并拥有自己的生命周期管理。

关于python - 取消任务会取消任务正在等待的 future 。它是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53277091/

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