首页 > 解决方案 > 如何在不等待的情况下安排等待顺序执行?

问题描述

假设,我有一些异步函数f1f2f3. 我想按顺序执行这些功能。最简单的方法是等待它们:

async def foo():
    await f1()
    # Do something else
    await f2()
    # Do something else
    await f3()
    # Do something else

但是,我并不关心这些异步函数的结果,我想在调度异步函数之后继续执行其余的函数。

asyncio 任务文档看来,这asyncio.ensure_future()可以帮助我。我使用以下代码对此进行了测试,并foo()根据我的期望使用了同步部分。但是,bar()从不执行过去 asyncio.sleep()

import asyncio

async def bar(name):
    print(f'Sleep {name}')
    await asyncio.sleep(3)
    print(f'Wakeup {name}')

async def foo():
    print('Enter foo')

    for i in [1, 2, 3]:
        asyncio.ensure_future(bar(i))
        print(f'Scheduled bar({i}) for execution')

    print('Exit foo')

loop = asyncio.get_event_loop()
loop.run_until_complete(foo())

上述代码的输出:

Enter foo
Scheduled bar(1) for execution
Scheduled bar(2) for execution
Scheduled bar(3) for execution
Exit foo
Sleep 1
Sleep 2
Sleep 3

那么,做我正在寻找的正确方法是什么?

标签: asynchronousasync-awaitpython-3.6python-asyncio

解决方案


我有一些异步函数f1f2f3. 我想按顺序执行这些功能。[...] 我想在调度异步函数后继续执行函数的其余部分。

直接的方法是使用辅助函数并让它在后台运行:

async def foo():
    async def run_fs():
        await f1()
        await f2()
        await f3()
    loop = asyncio.get_event_loop()
    loop.create_task(run_fs())
    # proceed with stuff that foo needs to do
    ...

create_task向事件循环提交协程。您也可以使用ensure_future它,但在生成协程时create_task首选。

问题中的代码有两个问题:首先,函数不是按顺序运行的,而是并行运行的。如上所示,通过在后台运行一个按顺序等待三个异步函数来解决此问题。第二个问题是,在 asyncio 中run_until_complete(foo())只等待foo()完成,而不是由产生的任务foo(尽管有解决此问题的 asyncio替代方案)。如果你想等待完成,必须等待它本身。run_until_complete(foo())run_fsfoo

幸运的是,这很容易实现 - 只需await在 末尾添加另一个foo(),等待run_fs之前创建的任务。如果此时任务已经完成,await则将立即退出,否则将等待。

async def foo():
    async def run_fs():
        await f1()
        await f2()
        await f3()
    loop = asyncio.get_event_loop()
    f_task = loop.create_task(run_fs())
    # proceed with stuff that foo needs to do
    ...
    # finally, ensure that the fs have finished by the time we return
    await f_task

推荐阅读