我试图理解 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
,但不能同时删除两者),而且代码的作用似乎完全相同。我觉得这很违反直觉,这里发生了什么? 感谢您的宝贵时间。
请您参考如下方法:
您提出了三种不同的场景:
- 没有
await
语句(注释掉两者) - 仅使用
await task1
(注释掉第二个) - 仅使用
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
两个任务都从挂起状态变为运行状态,现在 task1
和 task2
都完成了,因为 main()
正在等待一个任务~3 秒,足以让两个任务运行完成。
*这至少适用于我的设置(Mac OSX,...),但正如此处其他答案中所述,在其他设置中计时可能会有所不同,如果任务运行时间相似,两者都可能在情况 # 2 等地方运行。