我可以在 Python 中多次等待同一个任务吗?

Glo*_*eye 4 task python-asyncio python-3.9

我需要做很多工作,但幸运的是,很容易解耦到不同的任务中进行异步执行。其中一些是相互依赖的,我很清楚如何在任务中await与其他人一起获得结果。但是,我不知道如何让多个不同的任务等待同一个协程,并且都得到结果。据我所知,文档也没有提及这种情况。考虑以下最小示例:

from asyncio import create_task, gather

async def TaskA():
    ...  # This is clear
    return result

async def TaskB(task_a):
    task_a_result = await task_a
    ...  # So is this
    return result

async def TaskC(task_a):
    task_a_result = await task_a
    ...  # But can I even do this? 
    return result

async def main():
    task_a = create_task(TaskA())
    task_b = create_task(TaskB(task_a))
    task_c = create_task(TaskC(task_a))
    gather(task_b, task_c)  # Can I include task_a here to signal the intent of "wait for all tasks"?
Run Code Online (Sandbox Code Playgroud)

对于实际的脚本,所有任务都会执行一些数据库操作,其中一些涉及外键,因此依赖于已填充的其他表。有些依赖于同一张表。我绝对需要:

  1. 所有任务运行一次,且仅运行一次
  2. 有些任务依赖于其他任务在开始之前完成。

简而言之,问题是,这有效吗?我可以多次等待同一个实例化协程,并每次都得到结果吗?或者我需要将等待放入main()并传递结果吗?(这是当前的设置,我不喜欢它。)

小智 17

task您可以多次等待相同的操作:

from asyncio import create_task, gather, run


async def coro_a():
    print("executing coro a")
    return 'a'


async def coro_b(task_a):
    task_a_result = await task_a
    print("from coro_b: ", task_a_result)
    return 'b'


async def coro_c(task_a):
    task_a_result = await task_a
    print("from coro_a: ", task_a_result)
    return 'c'


async def main():
    task_a = create_task(coro_a())
    print(await gather(coro_b(task_a), coro_c(task_a)))


if __name__ == "__main__":
    run(main())
Run Code Online (Sandbox Code Playgroud)

将输出:

executing coro a
from coro_b:  a
from coro_a:  a
['b', 'c']
Run Code Online (Sandbox Code Playgroud)

你不能做的是等待相同的coroutine多次:

...

async def main():
    task_a = coro_a()
    print(await gather(coro_b(task_a), coro_c(task_a)))
...
Run Code Online (Sandbox Code Playgroud)

会提高RuntimeError: cannot reuse already awaited coroutine

只要您coro_a使用create_task代码安排协程就可以工作。