Python协程调度核心是单线程内由asyncio事件循环驱动的协作式并发,依赖await显式挂起恢复、I/O自动让出控制权,需用aiohttp等异步库避免阻塞。

Python 的协程调度核心是 asyncio 事件循环(Event Loop),它不依赖操作系统线程,而是在单线程内通过“挂起-恢复”机制协同调度多个异步任务。理解其模型的关键在于:**事件循环驱动、协程对象需显式 await、I/O 操作自动让出控制权**。
事件循环是调度中枢
每个 asyncio 程序有且仅有一个运行中的事件循环(除非手动创建多个)。它持续轮询 I/O 事件(如 socket 可读、定时器到期)、执行就绪的回调和协程,是整个异步调度的“大脑”。
- 调用
asyncio.run(main())会自动创建并启动一个事件循环 - 手动管理时可用
loop = asyncio.get_event_loop()(Python 3.11+ 推荐asyncio.get_running_loop()) - 循环一旦关闭,无法重启;新任务必须在新循环中提交
协程函数与协程对象要分清
async def 定义的是协程函数,调用它返回的是一个协程对象(coroutine object),此时函数体并未执行——它只是个待调度的“任务描述”。必须将它交给事件循环执行(例如用 await 或 asyncio.create_task())。
-
async def fetch(): return "done"→fetch()返回协程对象,不是结果 -
await fetch()才真正执行,并返回"done" -
asyncio.create_task(fetch())把协程包装成 Task 并立即调度,适合并发启动
I/O 操作是让出控制权的触发点
asyncio 的高效依赖于“可等待对象”(awaitable)对 I/O 的封装。真正的系统级阻塞调用(如 time.sleep()、requests.get())会卡住整个事件循环。必须使用 asyncio 原生支持的异步 I/O:
立即学习“Python免费学习笔记(深入)”;
- 网络请求用
aiohttp替代requests - 文件操作用
asyncio.to_thread()(Python 3.9+)或loop.run_in_executor()转移至线程池 - 延时用
await asyncio.sleep(1),而非time.sleep(1) - 所有底层基于
select/epoll/kqueue或 Windows 的IOCP实现
Task 和 Future 是调度的基本单元
协程被调度后,通常会被包装为 Task 对象(继承自 Future),代表一个正在运行或已完成的异步操作。Task 可被取消、查询状态、添加回调。
-
task = asyncio.create_task(coroutine)是推荐的并发启动方式 -
await task等待其完成;task.cancel()可中断执行(协程需响应CancelledError) -
asyncio.gather(a, b, c)并发运行多个协程并收集结果 -
asyncio.wait_for(task, timeout=2)为单个任务设置超时
不复杂但容易忽略:asyncio 不是多线程,也不是多进程,它靠协作式并发在单线程里榨干 I/O 等待时间。写 async 函数只是第一步,关键在用对 await 点、选对异步库、管好事件循环生命周期。










