首页 > 解决方案 > 为什么等待任务比等待协程更快?

问题描述

为什么等待任务比等待协程更快?

我正在查看文档https://docs.python.org/3/library/asyncio-task.html

特别是这个例子:

等待任务


async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)


async def main():
    task1 = asyncio.create_task(
        say_after(1, 'hello'))

    task2 = asyncio.create_task(
        say_after(2, 'world'))

    print(f"started at {time.strftime('%X')}")

    # Wait until both tasks are completed (should take
    # around 2 seconds.)
    await task1
    await task2

    print(f"finished at {time.strftime('%X')}")

与协程

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"started at {time.strftime('%X')}")

    await say_after(1, 'hello')
    await say_after(2, 'world')

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

标签: python-3.xtaskcoroutine

解决方案


等待任务并没有真正比等待协程更快。当您使用时,asyncio.create_task您正在为给定函数创建一个新任务,因此 python 为该函数创建一个任务并转到下一行。当您正在等待一项任务时,您只是在等待它完成。

import asyncio

async def task(delay, id):
    print(f'task with the id of {id} created (delay: {delay})')
    await asyncio.sleep(delay) # some calculation the takes time
    print(f'task {id} finished the heavy calculation')

async def main(loop):
    task1 = asyncio.create_task(task(3, 1))
    task2 = asyncio.create_task(task(5, 2))
    task3 = asyncio.create_task(task(1, 3))


loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
loop.run_forever()

正如您在这段代码中看到的,我们没有等待任务完成,每个任务都花时间完成。

解释:

  • task1- 创建一个立即执行该功能的任务
  • task2- 创建任务1后创建任务(创建未完成,同时task1功能仍在运行)
  • task3- 在创建所有任务后创建(同时运行 task1/2 的功能)
  • main函数完成执行并关闭
  • loop.run_forver()不让程序结束
  • 任务的输出

如果您删除该程序,loop.run_forever()则该程序将在不等待任务完成的情况下关闭,这就是为什么有时await您需要执行任务,因为您需要该值。

例如(相同的代码更改主函数):

async def main(loop):
    task1 = asyncio.create_task(task(3, 1))
    task2 = asyncio.create_task(task(5, 2))
    task3 = asyncio.create_task(task(1, 3))

    x = await task1


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

这只会等待 task1 完成并退出代码(没有loop.run_forever())。


推荐阅读