我如何等待未来期货的任何未来,可选择通知其他期货“不再需要它们”?
这就是我需要这个的原因。我想创建一种特殊的未来/任务来执行计时,如果它们累积超过一些超时(或者在与此计时任务交互后被迫停止),可以与其他期货/任务一起使用以取消它们。如果您熟悉Go,则它具有类似的概念Context
。
为了使这更加具体,想象一下。您有一个典型的HTTP客户端。它需要连续执行几个可能永远阻塞的操作,以便从URL请求页面。例如,这些操作可能是:
假设您允许整个操作花费一分钟。但是你也知道分配一个套接字不应该花费超过一毫秒,连接也可能需要一分钟,同样用于检索块。断开连接和资源释放应该花费几毫秒。
现在假设您要在每个项目符号点等待完全超时 - 嗯,您的配额超过了两倍。因此,您需要将每次调用的计算delta传递给其后继者。此外,假设您无法释放套接字 - 嗯,没什么大不了的,应用程序可能会从此错误中恢复,因此您还需要区分各种超时。我想这可能是这样写的(在一些想象中的Python版本中):
async def http_request(context, url):
socket = await min(allocate_socket(), context.timeout, socket_timeout)
await min(socket.connect(), context.timeout, connect_timeout)
async for chunk in min(socket.receive(), context.timeout, chunk_timeout):
print(chunk)
await min(socket.close(), context.timeout, close_timeout)
答案 0 :(得分:1)
async_timeout正是您所需要的,您的代码将如下所示:
from async_timeout import timeout
async def http_request(url):
async with timeout(timeout_for_all):
async with timeout(socket_timeout):
socket = await allocate_socket()
async with timeout(connect_timeout):
await socket.connect()
async with timeout(chunk_timeout):
async for chunk in socket.receive():
print(chunk)
async with timeout(close_timeout):
await socket.close()
让我们检查您提到的问题。
无论超时或其他任何事情,Go的样式Context也可以有cancel()方法允许 无论花费多少时间,都要从外部取消流程 等待。
asyncio
都有办法取消任何正在运行的任务。您应该在某个任务上调用cancel()方法(在其中会引发asyncio.CancelledError)并等待任务传播它(可能会抑制异常):
task.cancel()
with suppress(asyncio.CancelledError):
await task
这是在事情发生之前取消事物的标准方法。你不需要那么复杂的东西。
它也可以根据挂钟或内部计时器到期。
我不确定我是否理解这一点,但是async_timeout
能够准确地提供您想要的内容 - 一种在某个具体时间限制任务执行的方法。
在某种意义上,创建另外,如果没有直接在asyncio中实现,我担心 作为一个单独的线程,那么它将不得不等待预定的/ 阻止协程完成而不管超时(它只会 如果执行的协程进入,则能够取消执行 睡眠)。
asyncio
模块本身是为了避免使用多个线程。理想情况下,您的异步程序应该使用单线程内单个事件循环管理的许多协同程序。
这个常见的事件循环管理在它们发生时发生的事情。运行1秒后,此代码将引发TimeoutError
:
async with timeout(1):
await asyncio.sleep(20)
<强> UPD:强>
另一个例子是我需要等待多个工人 当我只关心他们中的一个时,完成某项任务 完成它,但我根本不关心超时。
也可以使用标准的asyncio功能来完成:
# Start 3 concurrent tasks (workers):
task_1 = asyncio.ensure_future(coro())
task_2 = asyncio.ensure_future(coro())
task_3 = asyncio.ensure_future(coro())
# Wait first of them done:
tasks = (task_1, task_2, task_3,)
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
print('done', done.pop().result())
# Cancel others since they're still running,
# but we don't need them to be finished:
for task in pending:
task.cancel()
with suppress(asyncio.CancelledError):
await task