我可以在 Python 中多次等待同一个任务吗?
Can I await the same Task multiple times in Python?
我需要做很多工作,但幸运的是,很容易解耦为不同的任务以异步执行。其中一些相互依赖,我非常清楚 on task 如何 await
多个其他人来获得他们的结果。但是,我不知道如何让多个不同的任务等待同一个协程,并且都得到结果。据我所知,Documentation 也没有提到这种情况。
考虑以下最小示例:
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"?
对于实际脚本,所有任务都进行一些数据库操作,其中一些涉及外键,因此取决于其他 tables 已经被填充。有些依赖于相同的 table。我绝对需要:
- 所有任务运行一次,而且只有一次
- 一些任务取决于其他任务在开始之前完成。
简而言之,问题是,这行得通吗?我可以多次等待同一个实例化协程,并且每次都得到结果吗?还是我 需要 将等待放入 main()
并传递结果? (这是当前的设置,我不喜欢它。)
您可以等待相同的 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())
将输出:
executing coro a
from coro_b: a
from coro_a: a
['b', 'c']
你不能做的是等待相同的 coroutine
倍数:
...
async def main():
task_a = coro_a()
print(await gather(coro_b(task_a), coro_c(task_a)))
...
将提高 RuntimeError: cannot reuse already awaited coroutine
.
只要您使用 create_task
安排协程 coro_a
,您的代码就可以工作。
实际上,您可以多次等待同一个任务,但它只会执行一次。
What does it mean?
任务有一些状态,例如待定、取消、完成等。一旦等待,它的状态就会变为完成,如果您再次等待它
它不会执行第二次,因为任务已经完成。
Then why do we need the tasks?
任务用于 运行 协程并发。当您使用 create_task
创建任务时,它会将协程添加到事件循环中。 gather
只是在参数中采用多个协同程序,并通过为它们创建任务来将它们并发添加到事件循环中 运行。
我需要做很多工作,但幸运的是,很容易解耦为不同的任务以异步执行。其中一些相互依赖,我非常清楚 on task 如何 await
多个其他人来获得他们的结果。但是,我不知道如何让多个不同的任务等待同一个协程,并且都得到结果。据我所知,Documentation 也没有提到这种情况。
考虑以下最小示例:
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"?
对于实际脚本,所有任务都进行一些数据库操作,其中一些涉及外键,因此取决于其他 tables 已经被填充。有些依赖于相同的 table。我绝对需要:
- 所有任务运行一次,而且只有一次
- 一些任务取决于其他任务在开始之前完成。
简而言之,问题是,这行得通吗?我可以多次等待同一个实例化协程,并且每次都得到结果吗?还是我 需要 将等待放入 main()
并传递结果? (这是当前的设置,我不喜欢它。)
您可以等待相同的 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())
将输出:
executing coro a
from coro_b: a
from coro_a: a
['b', 'c']
你不能做的是等待相同的 coroutine
倍数:
...
async def main():
task_a = coro_a()
print(await gather(coro_b(task_a), coro_c(task_a)))
...
将提高 RuntimeError: cannot reuse already awaited coroutine
.
只要您使用 create_task
安排协程 coro_a
,您的代码就可以工作。
实际上,您可以多次等待同一个任务,但它只会执行一次。
What does it mean?
任务有一些状态,例如待定、取消、完成等。一旦等待,它的状态就会变为完成,如果您再次等待它 它不会执行第二次,因为任务已经完成。
Then why do we need the tasks?
任务用于 运行 协程并发。当您使用 create_task
创建任务时,它会将协程添加到事件循环中。 gather
只是在参数中采用多个协同程序,并通过为它们创建任务来将它们并发添加到事件循环中 运行。