Python的异步编程和协程
2026/7/22 7:00:36 网站建设 项目流程

Python 的异步编程和协程是现代 Python 高并发网络编程(如 FastAPI、asyncio、AI Agent 框架)的核心。

很多习惯了 C++ 或 Java 等传统语言的开发者,刚接触 Python 异步时容易把它和“多线程”混淆。我们可以从底层原理、设计哲学、语法进化以及与多线程/C++ 的对比四个维度来彻底讲透。

一、 核心概念:什么是“协程”?

1. 协程 vs 线程 vs 进程

  • 进程(Process):操作系统分配资源的最小单位,拥有独立内存空间。切换开销极高。

  • 线程(Thread):操作系统调度的最小单位,共享进程内存。由 OS 内核强制抢占式调度(Preemptive Scheduling),存在内核态/用户态切换开销,多线程共享数据需要加锁(Mutex)。

  • 协程(Coroutine)用户态的轻量级“线程”。它不需要操作系统内核参与调度,而是由程序员/运行时在代码层面协作式调度(Cooperative Scheduling)

2. 协作式调度(关键特性)

  • 线程调度:OS 随时可能在某行代码中间“挂起”当前线程,去跑另一个线程(抢占)。

  • 协程调度:协程必须主动交出 CPU 控制权(在 Python 中通过await关键字),事件循环才会去安排执行其他协程。如果一个协程死循环不交出控制权,整个线程都会被卡死。

二、 为什么 Python 这么依赖协程?(底层动力:GIL)

在 C++ 中,如果需要处理高并发网络 IO,常见的做法是“线程池 + epoll (Reactor 模式)”

但在 Python(CPython 解释器)中,存在GIL(Global Interpreter Lock,全局解释器锁)

  • 无论你有多少个 CPU 核心,同一个 Python 进程在任意时刻只能有一个线程在执行 Python 字节码

  • 多线程的尴尬:在 Python 中用多线程处理 CPU 密集型任务,性能不仅不会提升,还会因为频繁的线程上下文切换和 GIL 争抢而变慢。

  • 协程的优势:既然多线程无法利用多核,且带年来锁竞争与内核切换开销,那么在单线程内用协程来搞定大量网络 IO就是成本最低、吞吐最高的方案!

三、 异步编程的核心“铁三角”

理解 Python 异步编程,只需要搞懂三个核心概念:

[ 事件循环 Event Loop ] <--- 调度管理 │ ├─── [ 协程 Task / Coroutine ] (遇到 await 主动 yield 控制权) ├─── [ 协程 Task / Coroutine ] └─── [ 协程 Task / Coroutine ]

1. 事件循环 (Event Loop)

  • 它是整个异步系统的心脏(底层基于 Linux 的epoll或 Windows 的IOCP)。

  • 它是一个无限循环,负责监控所有注册在它上面的 Socket/任务。当某个 Socket 可读/可写时,唤醒对应的协程继续向下执行。

2. 协程函数 (Coroutine Function)

  • async def定义的函数。

  • 调用async def函数不会立刻执行代码,而是返回一个“协程对象”。

3.await关键字

  • 只能在async def函数内部使用。

  • await expr的真正含义:“我在这里需要等待一个异步操作(如网络请求)完成,请事件循环把 CPU 控制权拿走去跑别的协程;等这个操作好了,再回来接着跑我后面的代码。”

也就是python始终都是单线程串行执行的?

答案是:在开启了asyncio协程的单进程中,代码确实始终运行在同一个线程上,并且在任意微观时刻(CPU 时间片内)只有一段代码在执行;但宏观上,它是通过“非阻塞交替”实现了“并发(Concurrency)”,而不是传统意义上死板的“同步串行”。

另外,如果放眼整个 Python 语言生态,Python并不是只能写单线程,它完全支持多线程和多进程。

我们可以从以下三个层次来精准理解:

1. 微观视角:是的,单线程单 Core,同一时间只做一件事

asyncio的模型下:

  • 整个程序只有一个主线程(Single Thread)。

  • 没有并行(Parallelism):如果你有两个 CPU 核心,asyncio无法同时利用这两个核心去跑两行 Python 代码。

  • 只要你的代码在做CPU 计算(例如x = 1 + 1或者 JSON 解析),Python 就会绝对串行地逐行执行,期间没有任何其他代码能插进来。

2. 宏观视角:它不是“同步等待”的串行,而是“非阻塞交替”的并发

传统“同步串行”和协程“异步并发”的最大区别,在于遇到 IO 阻塞(比如网络等待)时 CPU 在干什么

传统的“同步串行”
线程:[发请求A] ───(死等 1 秒 API 返回)───> [收到A] ──> [发请求B] ───(死等 1 秒 API 返回)───> [收到B] 总耗时:2 秒

CPU 有 99% 的时间都在白白干等网络数据包返回。

协程的“非阻塞并发”
线程:[发请求A] ──(遇到 await,交出控制权)──> [发请求B] ──(等待事件循环唤醒)──> [收到A/B] 总耗时:1 秒

当代码执行到await reader.readline()await http_client.get()时:

  1. 当前协程主动暂停,告诉事件循环:“我去等网络数据了,你先拿 CPU 去干别的。”

  2. 事件循环立刻切到另一个协程继续跑。

  3. 当网络数据包到达时,操作系统通知事件循环,事件循环再唤醒刚才暂停的协程恢复执行。

3. 放眼整个 Python 语言:Python 并不只有单线程

经常有人说“Python 是单线程的”,这其实是一个误区。你需要区分以下三个层面的概念:

机制线程/进程数适用场景核心特点
asyncio协程单线程超高并发网络 IO(如 AI Agent、Web API)极其轻量,用户态调度,无锁开销,但无法利用多核 CPU。
threading多线程多线程中等 IO 密集型(如多图下载、串口读取)受限于 GIL 锁,无法实现 CPU 算力的并行,但能做到多线程阻塞 IO 的并发。
multiprocessing多进程多进程CPU 密集型(如图像处理、矩阵计算、深度学习)每个进程有独立的 Python 解释器和独立 GIL,能够实现真正的多核 CPU 并行计算!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询