“RuntimeWarning: coroutine ‘xxx’ was never awaited” 看起来只是一条警告,背后却常常是整段逻辑根本没有执行、校验永远通过、任务悄悄丢失。这篇在本机把几种忘记 await 的写法逐个复现,看每一种的后果,以及默认警告为什么经常指错位置、怎么让它指对。
默认(退出码 0):
r 的类型 = coroutine | r = <coroutine object fetch at 0x10a437a00>
后面的代码照常往下走
/opt/homebrew/Cellar/python@3.15/3.15.0_1/Frameworks/Python. … 5/lib/python3.15/asyncio/events.py:94: RuntimeWarning: coroutine 'fetch' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
python -X tracemalloc=5(退出码 0):
r 的类型 = coroutine | r = <coroutine object fetch at 0x1061b3a00>
后面的代码照常往下走
/opt/homebrew/Cellar/python@3.15/3.15.0_1/Frameworks/Python. … 5/lib/python3.15/asyncio/events.py:94: RuntimeWarning: coroutine 'fetch' was never awaited
Object allocated at (most recent call last):
File "<tmp>/s2.py", lineno 6
python -X dev(退出码 0):
r 的类型 = coroutine | r = <coroutine object fetch at 0x109aad8d0>
后面的代码照常往下走
/opt/homebrew/Cellar/python@3.15/3.15.0_1/Frameworks/Python. … 5/lib/python3.15/asyncio/events.py:94: RuntimeWarning: coroutine 'fetch' was never awaited
Coroutine created at (most recent call last)
File "<tmp>/s3.py", line 9, in <module>
File "<tmp>/s3.py", line 6, in main
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
python -W error::RuntimeWarning(把这个警告当错误)(退出码 0):
这行照常执行
Exception ignored while finalizing coroutine <coroutine object fetch at 0x10a446080>:
msg, category=RuntimeWarning, stacklevel=2, source=coro
RuntimeWarning: coroutine 'fetch' was never awaited协程在别处被销毁时,默认的警告指向 asyncio 内部的行;-X tracemalloc 或 -X dev 才能看到创建它的位置。-W error 只会变成 Exception ignored。
例子(退出码 0):
asyncio.sleep(1) 没 await:用了 0.0046 s
await asyncio.sleep(0.3):用了 0.30 s
save("A") 没 await,0.3 s 之后 done = []
await save("B") 之后 done = ['B']
<tmp>/s5.py:7: RuntimeWarning: coroutine 'sleep' was never awaited
t0 = time.perf_counter(); asyncio.sleep(1); print(f'asyncio.sleep(1) 没 await:用了 {time.perf_counter() - t0:.4f} s')
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
<tmp>/s5.py:9: RuntimeWarning: coroutine 'save' was never awaited
save('A'); await asyncio.sleep(0.3); print('save("A") 没 await,0.3 s 之后 done =', done)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback函数体不执行,程序继续往下走。asyncio.sleep 不睡、保存逻辑不发生。
例子(退出码 0):
is_valid(5) 没 await:当作 True,放行
await is_valid(5):通过
is_valid(-5) 没 await:当作 True,放行
await is_valid(-5):不通过
bool(is_valid(-5)) = True
<tmp>/s6.py:7: RuntimeWarning: coroutine 'is_valid' was never awaited
if is_valid(v): print(f'is_valid({v}) 没 await:当作 True,放行')
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
<tmp>/s6.py:10: RuntimeWarning: coroutine 'is_valid' was never awaited
print('bool(is_valid(-5)) =', bool(is_valid(-5)))
RuntimeWarning: Enable tracemalloc to get the object allocation traceback协程对象永远为真,校验类的判断形同虚设。
没跑完的任务(退出码 0):
main 返回时 log = ['awaited 0.2s']
asyncio.run 结束之后 log = ['awaited 0.2s'] (0.5 秒的那个被取消了)
任务抛了异常、没人 await(退出码 0):
Task exception was never retrieved
future: <Task finished name='Task-2' coro=<boom() done, defined at <tmp>/s8.py:3> exception=ValueError('boom')>
File "<tmp>/s8.py", line 3, in boom
async def boom(): raise ValueError('boom')
ValueError: boomasyncio.run 结束时没跑完的任务丢掉;任务里的异常没人取回只会在回收时打印。需要保证做完就保存引用并 await。
耗时对比(退出码 0):
3 个任务各 time.sleep(0.2):总共 0.61 s(串行)
3 个任务各 await asyncio.sleep(0.2):总共 0.20 s(并发)
asyncio.run(main(), debug=True) 里 time.sleep(0.2)(退出码 0):
Executing <Task finished name='Task-1' coro=<main() done, de … s/Python.framework/Versions/3.15/lib/python3.15/asyncio/runners.py:110> took 0.201 secondstime.sleep 会阻塞整个循环,并发退化为串行,debug 模式会提示哪一步用了多久。