【问题标题】:Asyncio execution flow issueAsyncio 执行流程问题
【发布时间】:2020-03-29 19:49:14
【问题描述】:

我对 python 中的 asyncio 有点陌生。我试图运行这个简单的代码,但我不知道为什么会得到这个意外的输出。

我所做的是,在outer 函数中,我创建了异步任务并将其存储在数组tasks 中。在等待这些任务之前,我写了一个打印语句print("outer"),它应该在每次迭代中运行。在任务中,我在inner 函数中写了另一个打印语句print("inner")。但是有些我得到了一些意想不到的输出。

这是代码 -

import asyncio


def main():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(outer(loop))
    loop.close()


async def outer(loop):
    tasks = []
    for i in range(0, 5):
        tasks.append(loop.create_task(inner()))

    for task in tasks:
        print("outer")
        await task


async def inner():
    print("inner")
    await asyncio.sleep(0.5)

if __name__ == '__main__':
    main()

这是输出 -

outer
inner
inner
inner
inner
inner
outer
outer
outer
outer

我的预期输出是 -

outer
inner
outer
inner
outer
inner
outer
inner
outer
inner

为什么所有inner 都在outer 之前打印。 asyncio 的正确执行流程是什么?提前致谢。

【问题讨论】:

  • 每个任务/协程 runs 直到 await 语句然后它被暂停。您的示例类似于文档中的 coroutine example 具有相似的结果。
  • 来自the docs - While a Task is running in the event loop, no other Tasks can run in the same thread. When a Task executes an await expression, the running Task gets suspended, and the event loop executes the next Task.
  • 但是当一个任务被等待时,为了开始一个新任务,事件循环必须执行下一个for循环迭代。如果这是真的,那么outer 应该已经被打印出来了。

标签: python asynchronous async-await python-asyncio


【解决方案1】:

async def outer(loop)

for i in range(0, 5):
    tasks.append(loop.create_task(inner()))
  • 五个新的inner 任务已创建、计划并开始运行。
  • 事件循环运行计划任务直到它们完成。

如果您在innerouter 中添加更多内容,则可以更好地显示此过程:

async def outer(loop):
    tasks = []
    for i in range(0, 5):
        tasks.append(loop.create_task(inner(i)))
    await asyncio.sleep(3)
    for task in tasks:
        print('outer')
        await task

async def inner(n):
    print(f"inner {n} start")
    await asyncio.sleep(0.5)
    print(f'inner {n} end')
  • outer 在睡觉时

    • 第一个任务运行到它的 await 语句
    • 事件循环暂停第一个任务的执行
    • 事件循环运行下一个调度任务直到它的 await 语句
    • 这会一直持续到每个任务都有机会运行到它的 await 语句,然后事件循环开始四处查看是否有任何任务完成等待它们正在等待的任何东西 - 如果完成它让它们运行一些更多。
    • 这会一直持续到所有任务完成
  • 您可以看到五个任务在第二个 for 循环开始之前执行并完成。

  • 在第二个 for 循环中,每个任务都已完成,因此 await task 无需等待,outer 连续打印五次。

我对控制一切的事件循环有点模糊——我还没有找到任何明确的文档——可能在create_task 文档中提到:Wrap the coro coroutine into a Task and schedule its execution. 当您创建任务时,它会被安排。我在 pyvideo.org 上看到了显示该过程的视频,遗憾的是我无法快速找到我想要链接到的视频。

【讨论】:

  • 你找到解释完整过程的 pyvideo.org 链接了吗?
  • @shikharsrivastava 它躲避我。有太多需要观看/重新观看才能找到它。我什至可能记错了很多部分——认为它们是一体的。
【解决方案2】:

loop.create_task(inner())立即将所有 5 个inner 任务排队等待运行,而不是await taskawait task 暂停 outer 直到第一个任务完全完成,即至少 0.5 秒。在此期间,所有inner 任务都已在await 上运行一次,包括它们的print


async def outer(loop):
    tasks = []
    for i in range(0, 5):
        # queues task immediately
        tasks.append(loop.create_task(inner()))

    for task in tasks:
        print("outer")
        # suspends for at least 0.5 seconds
        await task


async def inner():
    # runs immediately
    print("inner")
    await asyncio.sleep(0.5)

【讨论】:

  • 啊哈!!如果您在创建任务的循环之后添加await asyncio.sleep(10); print('outer done sleeping',您可以看到它们在等待任何任务之前运行。谢谢
猜你喜欢
  • 2021-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多