Python异步编程的核心是协程与事件循环协同工作:协程需由事件循环调度执行,async def定义协程函数,调用返回协程对象,须通过asyncio.run()、create_task()或await触发运行;事件循环负责I/O监听、协程调度与任务管理;await表示让出控制权,仅适用于awaitable对象;常见错误包括忘记await、混用同步阻塞调用、误用time.sleep等。

Python异步编程的核心是协程(coroutine)与事件循环(event loop)的配合。协程本身不会自动运行,必须由事件循环调度执行;理解二者关系,是写出可靠异步代码的前提。
协程函数 ≠ 协程对象 ≠ 正在运行的任务
定义一个 async def 函数,只是创建了一个协程函数,调用它返回的是一个协程对象(coroutine object),不是立即执行,也不会启动异步行为。
例如:
async def fetch_data():
await asyncio.sleep(1)
return "done"
立即学习“Python免费学习笔记(深入)”;
执行 fetch_data() 得到的是一个协程对象,打印出来类似 。此时什么都没发生。
要让它跑起来,得交给事件循环:
- 用
asyncio.run(fetch_data())—— 自动创建新事件循环并运行,适合脚本入口 - 用
loop.create_task(coro)或asyncio.create_task(coro)—— 把协程包装成任务(Task),加入当前事件循环待调度 - 用
await coro—— 在另一个协程内部等待它,此时调用者协程会挂起,直到被等待的协程完成
事件循环是异步程序的“调度中心”
事件循环负责:监听 I/O 就绪、调度协程恢复、管理任务生命周期、处理回调和定时器。它不并发执行 Python 字节码,而是通过挂起/恢复协程实现单线程内的协作式并发。
Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。它虽然不是Linux系统核心的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序,深入了解和熟练掌握shell的特性极其使用方法,是用好Linux系统
关键事实:
- 一个线程最多运行一个事件循环(主线程默认无循环,需显式启动)
-
asyncio.run()每次都新建并关闭循环,不能在已有循环中重复调用 - 在 Jupyter 或某些框架(如 FastAPI)中,循环可能已由环境启动,直接调用
asyncio.run()会报错 “event loop is running” - 获取当前循环:用
asyncio.get_running_loop()(推荐),而非过时的get_event_loop()
await 的本质是“让出控制权”
await 表达式只能出现在协程函数中,它的作用不是“等待时间过去”,而是告诉事件循环:“我现在要等某个东西(比如网络响应、文件读取、另一个协程),请先去干别的,等它就绪了再回来叫我。”
能被 await 的对象必须是 awaitable,包括:
- 协程对象(
async def返回值) - 实现了
__await__方法的对象(如asyncio.Future、asyncio.Task) - 使用
types.coroutine装饰的生成器函数(较少见)
普通函数、列表、字符串等不可 await,否则抛 TypeError: object xxx can't be used in 'await' expression。
常见误区与调试提示
新手容易卡在这几个地方:
- 忘记 await:调用协程函数却不 await,只得到协程对象,后续逻辑不会执行(也没有报错)
-
混用同步阻塞调用:在协程里写
time.sleep(2)或requests.get(),会阻塞整个事件循环,失去异步意义 - 误以为 asyncio.sleep = 真实休眠:它只是向事件循环注册一个“1秒后唤醒我”的计划,期间循环可调度其他任务
-
多任务没并发执行:用
await task1(); await task2()是串行;要用await asyncio.gather(task1(), task2())或asyncio.create_task()并发启动
调试时可加 print(f"running at {time.time():.2f}") 观察实际执行顺序,比想象中更贴近“多任务交替推进”而非“同时运行”。










