簡體   English   中英

異步python函數調用,在asyncio.gather中保持重新調度函數,無需等待最長運行任務

[英]Asynchronous python function calls, keep rescheduling functions in asyncio.gather without waiting for longest running task

所以目前我有如下所示的異步 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)

這段代碼的問題在於它總是等待運行時間最長的get_output調用來為所有輸出源再次調用該函數。

我想知道如何重寫此代碼,以便在每個output_source完成后立即為每個output_source調用每個get_output調用(如果它在upper_bound_wait 內),我還希望每個get_output函數調用延遲而不是在它完成所有這些之后。

如何使用 asyncio 實現這一點?

建議:將您的所有邏輯移至協程並在一個簡單的循環中創建任務。 每個任務將自行決定何時延遲、何時重復以及何時退出。

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))

您可以在循環asyncio.waitFIRST_COMPLETED一起使用。 您需要將原始源存儲在某處,例如在傳遞給asyncio.wait並從asyncio.wait返回的 future/task 對象上。 這樣循環就可以使用相同的源重新調用get_output來重新調度它。 同樣,為了使 per- get_output invocation 延遲,您需要存儲每個先前調用的開始時間,可能也在未來/任務中。 例如(未經測試):

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM