async函数调用后立刻返回一个coroutine对象,该对象未执行,仅表示待调度的异步任务;必须通过await或asyncio.run()驱动运行。
调用 async def 定义的函数,不会真正执行函数体,而是立即返回一个 coroutine 对象。这个对象本身不运行,只是个待调度的

常见错误是直接打印或忽略返回值,误以为函数已执行:
async def fetch_data():
return "done"
result = fetch_data() # ← 这里 result 是
print(result) # ,不是 "done"
await(在另一个 async 函数内)或 asyncio.run() 驱动它运行await 只能在 async def 函数内部使用,不能在普通函数或交互式顶层直接写result + "!" 会报 TypeError: unsupported operand type(s)
await 不是“等待完成”,而是“让出控制权,挂起当前协程,把 CPU 让给事件循环去跑别的协程”。它只在遇到真正的异步挂起点(如 asyncio.sleep()、aiohttp.get()、await asyncio.Lock().acquire())时才暂停;纯计算不会挂起。
示例中看似“同步”的代码,实际可能不阻塞:
async def work():
print("start")
await asyncio.sleep(0) # ← 真正的挂起点
print("after sleep")
x = sum(i for i in range(10**6)) # ← 纯计算,不挂起,会阻塞整个事件循环await 后面必须是可等待对象(Awaitable),比如 coroutine、Task、Future,不能是普通函数返回值或数字await 42 会报 TypeError: object int can't be used in 'await' expression
await 同一个协程对象会报 RuntimeError: cannot reuse already awaited coroutine
asyncio.run(main()) 不只是启动协程,它会:新建一个事件循环、把 main() 包装成 Task、运行直到完成、然后关闭循环并清理所有未完成的 Task(触发 CancelledError)。
这意味着:
asyncio.get_event_loop() 的脚本)重复调用 asyncio.run(),会报 RuntimeError: asyncio.run() cannot be called from a running event loop
main() 内部启用了后台 Task(如 asyncio.create_task(...)),且没显式 await 或 asyncio.wait_for(),它们可能被强制取消asyncio.run() 总是创建新循环,所以无法跨调用共享 asyncio.Queue 或 asyncio.Event 等对象用 asyncio.create_task() 提交的协程会立即被调度,但它的完成时间不可控——你得自己决定是否等待它、如何捕获异常、是否允许它在主协程退出后继续跑。
典型陷阱:
async def background_job():
await asyncio.sleep(2)
print("done")
async def main():
asyncio.create_task(background_job()) # ← 没有变量接收,也没 await
await asyncio.sleep(0.1) # 主协程很快结束
这段代码大概率看不到 "done" 输出,因为 background_job() 被创建后还没来得及执行完,事件循环就退出了。
task = asyncio.create_task(...),再用 await task 或 asyncio.gather(task, ...)
asyncio.shield(task) 防止被取消,或用 asyncio.create_task(..., name="xxx") 方便调试task.exception() 主动检查真正难的不是语法,是判断某段逻辑该不该拆成 async、哪个 await 实际构成瓶颈、以及什么时候该用 Task 而不是链式 await。这些没法靠记住规则解决,得看 asyncio.Task.all_tasks() 和 asyncio.current_task() 在运行时吐出什么。