如何同时执行多个协程并在某些协程完成时执行某些操作?

How to execute multiple coroutines concurrently and do something when some coroutines finishes?

上下文

我有三个食谱 类,它们共享一个共同的成分。


class BrewedNoodle:
    ingredients: list[Coroutine] = [Noodle]

    async def cook(noodle: Noodle):
        pass

class PorkNoodle:
    ingredients: list[Coroutine] = [Noodle, Pork]

    async def cook(noodle: Noodle, pork: Pork):
        pass


class BeefNoodle:
    ingredients: list[Coroutine] = [Noodle, Beef]

    async def cook(noodle: Noodle, beef: Beef):
        pass

请将每个成分视为一个API(需要网络调用)

我想做什么

我想执行 asyncio.gather() 以同时获取(准备)每种成分。 一旦为特定食谱准备好所有必要的食材,我想立即烹饪,而不是等待其他食材。

例如:

  1. 面条一做好,我就煮BrewedNoodle。
  2. 猪肉准备好了,(因为面条和猪肉都准备好了)然后我煮猪肉面。
  3. 牛肉准备好后,我煮牛肉面。

我实际做了什么

但我在等待asyncio.gather(),我注定要等到所有材料都准备好。 (即使面条做好了也无法预煮BrewedNoodle)

# prepare ingredients
noodle, pork, beef = await asyncio.gather(Noodle(), Pork(), Beef())


# cook
BrewedNoodle().cook(noodle)
PorkNoodle().cook(noodle, pork)
BeefNoodle().cook(noodle, beef)

问题

如何在必要的食材准备就绪的情况下不等待其他食材来烹饪食谱?

如果我对您的示例的理解正确,则需要某种从成分到可以从中创建的菜肴的明确映射。其他菜肴需要 Noodle 的特殊情况也需要单独解决。算法的核心是asyncio.as_completed():

dishes = {
    Noodle: BrewedNoodle,
    Pork: PorkNoodle,
    Beef: BeefNoodle,
}
ingredients = [Noodle(), Pork(), Beef()]
noodle = None
for coro in asyncio.as_completed(ingredients):
    ingredient = await coro
    dish = dishes[type(ingredient)]
    if isinstance(ingredient, Noodle):
        dish.cook(ingredient)
        noodle = ingredient
    else:
        # Pork or Beef, assuming noodle has already finished
        dish.cook(noodle, ingredient)