[英]Asynchronous python function calls, keep rescheduling functions in asyncio.gather without waiting for longest running task
So currently i have asynchronous python code (using asyncio) that looks like this:所以目前我有如下所示的异步 python 代码(使用 asyncio):
while datetime.now() < time_limit:
last_start_run_time = datetime.now()
result = await asyncio.gather(
*(
get_output(output_source)
)
for output_source in output_sources
)
for output in res:
output_dict.update(my_output_dict)
if (datetime.now() - last_start_run_time).seconds < upper_bound_wait:
await asyncio.sleep(delay)
The problem with this code is that it always waits for the longest running get_output call to call the function again for all output sources.这段代码的问题在于它总是等待运行时间最长的get_output调用来为所有输出源再次调用该函数。
I am wondering how can i rewrite this code in a way that calls each get_output call for each output_source as soon as it had finished it's earlier run (if it is within the upper_bound_wait ), i would also like the delay to be per get_output function call rather than after it finishes all of them.我想知道如何重写此代码,以便在每个output_source完成后立即为每个output_source调用每个get_output调用(如果它在upper_bound_wait 内),我还希望每个get_output函数调用延迟而不是在它完成所有这些之后。
How can this be achieved used asyncio?如何使用 asyncio 实现这一点?
Suggestion: move all your logic to a coroutine and create the tasks in a simple loop.建议:将您的所有逻辑移至协程并在一个简单的循环中创建任务。 each task will decide for itself when to delay, when to repeat, and when to exit.
每个任务将自行决定何时延迟、何时重复以及何时退出。
async def get_output_repeatable(upper_bound_wait, output_source):
while datetime.now() < time_limit:
last_start_run_time = datetime.now()
output_dict.update(await get_output(output_source))
if (datetime.now() - last_start_run_time).seconds < upper_bound_wait:
await asyncio.sleep(delay)
def run_them_all():
for output_source in output_sources:
asyncio.create_task(get_output_repeatedly(upper_bound_wait, output_source))
You can use asyncio.wait
with FIRST_COMPLETED
in a loop.您可以在循环
asyncio.wait
与FIRST_COMPLETED
一起使用。 You'll need to store the original source somewhere, eg on the future/task objects which are both passed to and returned from asyncio.wait
.您需要将原始源存储在某处,例如在传递给
asyncio.wait
并从asyncio.wait
返回的 future/task 对象上。 That way the loop can reinvoke get_output
with the same source to reschedule it.这样循环就可以使用相同的源重新调用
get_output
来重新调度它。 Likewise, to make the delay per- get_output
-invocation, you'll need to store the start time of each previous invocation, probably also on the future/task.同样,为了使 per-
get_output
invocation 延迟,您需要存储每个先前调用的开始时间,可能也在未来/任务中。 For example (untested):例如(未经测试):
async def delayed_run(aw):
await asyncio.sleep(delay)
return await aw
async def run_sources(output_sources, time_limit, upper_bound_wait):
output_dict = {}
pending = set()
for output_source in output_sources:
fut = asyncio.create_task(get_output(output_source))
fut.my_start_time = time.time()
fut.my_source = output_source
pending.add(fut)
while pending and time.time() < time_limit:
done, pending = await asyncio.wait(
pending, return_when=asyncio.FIRST_COMPLETED,
timeout=time_limit - time.time())
for done_fut in done:
output_dict.update(done_fut.result())
new_coro = get_output(done_fut.my_source)
if time.time() - done_fut.my_start_time < upper_bound_wait:
new_coro = delayed_run(new_coro)
new_fut = asyncio.create_task(new_coro)
new_fut.my_start_time = time.time()
new_fut.my_source = done_fut.my_source
pending.add(new_fut)
return output_dict
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.