【发布时间】:2022-10-08 09:11:55
【问题描述】:
请看下面的代码(为了简单起见,我没有使用 pydantic 来对 corutine、重试、超时进行分组):
import asyncio
import typing as tp
import random
async def my_func(wait_time: int) -> str:
random_number = random.random()
random_time = wait_time - random_number if random.random() < 0.5 else wait_time + random_number
print(f"waiting for {wait_time}{random_time:+} seconds")
await asyncio.sleep(wait_time)
return f"waited for {wait_time}{random_time:+} seconds"
async def main() -> None:
task1 = asyncio.create_task(my_func(wait_time=1), name='task1')
task2 = asyncio.create_task(my_func(wait_time=2), name='task2')
task3 = asyncio.create_task(my_func(wait_time=3), name='task3')
task1_timeout = 1.2
task2_timeout = 2.2
task3_timeout = 3.2
task1_retry = 4
task2_retry = 3
task3_retry = 2
total_timeout = 5
<what to put here?>
return task1_result, task2_result, task3_result
asyncio.run(main())
如您所见,我有函数 my_func (在现实生活中我将有多个不同的函数)。 在 main() 中,我定义了 3 个任务。每个任务都有其超时和重试。 例如,task1 超时 2 秒,重试 3 次。
此外,我还有另一个(全局)超时,total_timeout,它表示 main() 必须完成的时间。
例如,如果task1 开始运行并且在 1.2 秒内没有得到结果,我们应该最多重试 4 次,所以在我们根本无法得到结果的情况下,我们仍然低于 timeout_total 的 5秒。
对于task2,在2.2秒内超时,可以重复3次,在4.4秒第二次重复完成后,如果我们再次重试,它将在第5秒被total_timeout截断。
对于task3,如果我们第一次尝试没有完成,我们没有足够的时间进行第二次尝试(total_timeout)。
我想同时执行所有三个任务,尊重他们各自的超时和重试,以及total_timeout。最后,最多 5 秒后,我将得到三个元素的元组,它们将是 str(my_func 的输出)或 None(以防所有重复失败,或任务已被 total_timeout 切断)。
所以输出可以是(str, str, str)、(str, None, str) 或(None, None, None)。
有人可以提供一些示例代码来完成我所描述的吗?
【问题讨论】:
-
你需要像
await asyncio.gather(task1, task2, task3)这样的东西。这将返回三个结果,以便您传入等待对象。但请记住,asyncio 不会同时运行。它允许一个任务在一个或多个其他任务等待 I/O 完成时运行。 -
收集根本没有超时
-
你应该使用
wait_for而不是create_task。这几乎是整个timeouts section of the docs。 -
是的,这听起来很容易。你有超时的wait_for(但是一个等待的),你有多个等待超时的等待,你有没有超时的聚集......有很多选择,但我还没有看到有人为什么提供了解决方案我已经描述过了。我认为这是许多人可以从中受益的事情。
-
您尝试过哪些?他们中的任何一个工作了吗?如果它们不起作用,那么每个版本有什么问题?
标签: python timeout python-asyncio retry-logic