Skip to main content
 首页 » 编程设计

python asyncios create_task 和 await 函数

2024年09月07日10lyhabc

我试图理解 python 的 asynico 模块,并在 https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task 上遇到了以下代码段

import time 
import asyncio 
 
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('started at', time.strftime('%X')) 
 
    # Wait until both tasks are completed (should take 
    # around 2 seconds.) 
    await task1 
    await task2 
 
    print('finished at', time.strftime('%X')) 
 
asyncio.run(main()) 

事实证明,可以简单地删除 await task2(或 task1,但不能同时删除两者),而且代码的作用似乎完全相同。我觉得这很违反直觉,这里发生了什么? 感谢您的宝贵时间。

请您参考如下方法:

您提出了三种不同的场景:

  1. 没有 await 语句(注释掉两者)
  2. 仅使用await task1(注释掉第二个)
  3. 仅使用await task2(注释掉第一个)

这是您的脚本;为便于说明,稍微延长 task2 的 sleep 时间。

# tasktest.py 
import time 
import asyncio 
 
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(3, 'world')) 
 
    print('started at', time.strftime('%X')) 
    await task1 
    # await task2 
    print('finished at', time.strftime('%X')) 
 
asyncio.run(main()) 

1。没有 await 语句

这是 asyncio.run() 的内容:

loop = events.new_event_loop() 
try: 
    events.set_event_loop(loop) 
    loop.set_debug(debug) 
    return loop.run_until_complete(main)   # < ----- 
finally: 
    try: 
        _cancel_all_tasks(loop)            # < ----- 
        loop.run_until_complete(loop.shutdown_asyncgens()) 
    finally: 
        events.set_event_loop(None) 
        loop.close() 

重要的是,循环关心main() 是否完成,然后取消与正在运行的事件循环关联的所有其他任务。 (每个任务在指定时都是 tied to 事件循环。)

如果您定义 main() 时没有任何 await 语句,create_task() 会安排要执行的任务,但是 main () 不等待其中任何一个完成。

2。 等待任务1

设置:

await task1 
# await task2 

输出:

(base_py37) $ python3 tasktest.py  
started at 11:06:46 
hello 
finished at 11:06:47 

两个任务都从挂起状态变为运行状态,但只有 task1 完成,因为 main() 只等待一个大约需要 1 秒的任务,时间不够 task2 运行。*(注意 main() 只需要 1 秒。)

3。 等待任务2

设置:

# await task1 
await task2 

输出:

(base_py37) $ python3 tasktest.py  
started at 11:08:37 
hello 
world 
finished at 11:08:40 

两个任务都从挂起状态变为运行状态,现在 task1task2 都完成了,因为 main() 正在等待一个任务~3 秒,足以让两个任务运行完成。


*这至少适用于我的设置(Mac OSX,...),但正如此处其他答案中所述,在其他设置中计时可能会有所不同,如果任务运行时间相似,两者都可能在情况 # 2 等地方运行。