为什么asyncio.run()或loop.run_until_complete()会运行已创建但未等待的任务?

问题描述 投票:0回答:1

这是代码。

import asyncio

async def run_test():
    print("run1")
    await asyncio.sleep(1)
    print("run2")

async def main():
    print("main1")
    loop = asyncio.get_event_loop()
    task = loop.create_task(run_test())
    #task = asyncio.create_task(run_test())
    #task = asyncio.ensure_future(run_test())
    print("main2")

print("________________")
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
print("________________")

我期待类似的输出

________________
main1
main2
________________

因为任务尚未等待。但输出实际上是

________________
main1
main2
run1
________________

如果我在 run_test() 中删除 async.sleep() ,它就会变成这样:

________________
main1
main2
run1
run2
________________

我也尝试过

    #task = asyncio.create_task(run_test())
    #task = asyncio.ensure_future(run_test())

结果是一样的。 3个问题:

  1. 为什么 run_test() 没有等待就运行了?
  2. 有没有办法创建一个任务而不将其放入事件循环?
  3. run_until_complete() 不应该在 main() 完成后立即返回吗? 我的猜测是,事件循环在 main() 完成后继续运行可运行任务,并在没有更多可运行任务时返回。但这与名称“run_until_complete”冲突。 main() 完成后实际上发生了什么?
python-3.x python-asyncio event-loop python-3.11
1个回答
0
投票

事件循环的单次迭代”(称为

run_once()
)包括连续运行每个“就绪任务”,直到没有就绪任务为止。

“就绪任务”是当前未产生的计划任务(即不等待

asyncio.sleep()
)。

函数

loop.run_until_complete(main())
的工作原理如下(简而言之):

task = self.create_task(main())
while not task.completed:
  self.run_once()

我们通过调用

run_once()
开始事件循环的第一次迭代。在第一次迭代中,会发生以下情况:

  1. main()
    是一个“就绪任务”,因此它开始执行
    • print("main1")
      输出“main1”
    • asyncio.create_task(run_test())
      将新任务添加到循环中。处于“就绪”状态
    • print("main2")
      输出“main2”
    • main()
      返回,完成任务
  2. run_test()
    是一个“就绪任务”,因此它开始执行
    • print("run1")
      输出“run1”
    • await asyncio.sleep(1)
      使任务屈服,将控制权返回给循环。设置一个属性来标记该任务将在未来 1 秒再次准备好。
  3. 没有更多正在运行的任务,因此事件循环的第一次迭代已完成。

现在

main()
任务已完成,
run_until_complete
将不会启动事件循环的另一次迭代,并且您的程序将退出。请注意,
run_test()
任务从未有机会完成。

© www.soinside.com 2019 - 2024. All rights reserved.