让我们说我们有一些任务(子任务)应该在外部任务完成时完成。我们无法控制外部任务:我们不知道它何时完成(它可以在子任务完成之前发生),我们不能等待内部的子任务。
在此片段中,我们将收到警告,因为外部任务在子任务之前完成:
import asyncio
def create_sub_task():
sub_task = asyncio.ensure_future(sub())
# We want this sub_task to be finished when outer task done
async def sub():
await asyncio.sleep(2)
print('sub done')
async def main(): # main is outer task for sub_task
create_sub_task()
await asyncio.sleep(1)
print('outer done')
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
add_done_callback
看起来像是一种在外部任务完成时抓住时刻的方法,但是我们不能在这里等待子任务:这个函数是同步的。
我找到的方法是使用事件循环的私有_run_once
函数来同步在回调内完成任务:
import asyncio
from functools import partial
def create_sub_task():
sub_task = asyncio.ensure_future(sub())
# Callback to wait for sub_task
outer_task = asyncio.Task.current_task()
outer_task.add_done_callback(partial(_stop_task, sub_task))
async def sub():
await asyncio.sleep(2)
print('sub done')
def _stop_task(sub_task, task):
# Ugly way to wait sub_task finished:
loop = asyncio.get_event_loop()
while not sub_task.done():
loop._run_once()
async def main(): # main is outer task for sub_task
create_sub_task()
await asyncio.sleep(1)
print('outer done')
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
它有效,但它有许多可能出现问题的丑陋方式。
如何更好地解决任务?
答案 0 :(得分:1)
AFAIK如果没有内部原因,就无法解决这个问题。我个人会在一个未来asyncio.gather
外部和子任务,然后重写回调。
不幸的是Future的回调列表没有公开接口公开(我正在使用_callbacks
):
import asyncio
def create_sub_task():
sub_task = asyncio.ensure_future(sub())
outer_task = asyncio.Task.current_task()
multi_fut = asyncio.gather(sub_task, outer_task)
for cb in outer_task._callbacks:
multi_fut.add_done_callback(cb)
outer_task.remove_done_callback(cb)
async def sub():
await asyncio.sleep(2)
print('sub done')
async def main(): # main is outer task for sub_task
create_sub_task()
await asyncio.sleep(1)
print('outer done')
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
我认为你不想要或者你不能改变流程,但我鼓励你重新思考。也许发布一些上下文 - 约束起源。