2. 并发与异步编程
Python 提供了多种并发编程模型,理解它们的特点和适用场景是写出高效程序的关键。
2.6. 并发 vs 并行
graph TD
A[并发编程] --> B[并发 Concurrency]
A --> C[并行 Parallelism]
B --> D[单核心<br>任务交替执行]
C --> E[多核心<br>任务同时执行]
D --> F[线程/协程]
E --> G[多进程]
2.6.1. 概念区分
特性 |
并发 (Concurrency) |
并行 (Parallelism) |
|---|---|---|
定义 |
同时处理多个任务 |
同时执行多个任务 |
CPU |
可以是单核 |
需要多核 |
Python 实现 |
线程、协程 |
多进程 |
适用场景 |
I/O 密集型 |
CPU 密集型 |
2.6.2. Python 并发模型选择
# 场景分析
# 1. I/O 密集型(网络请求、文件操作、数据库查询)
# 推荐:asyncio(首选)或 threading
# 原因:等待 I/O 时可以切换到其他任务
# 2. CPU 密集型(数值计算、图像处理、数据分析)
# 推荐:multiprocessing 或 concurrent.futures.ProcessPoolExecutor
# 原因:绕过 GIL,利用多核
# 3. 混合型
# 推荐:组合使用,或使用 Ray、Dask 等框架
2.7. 快速对比
import time
import threading
import multiprocessing
import asyncio
def io_bound_task():
"""I/O 密集型任务"""
time.sleep(1)
return "done"
def cpu_bound_task(n):
"""CPU 密集型任务"""
total = 0
for i in range(n):
total += i * i
return total
async def async_io_task():
"""异步 I/O 任务"""
await asyncio.sleep(1)
return "done"
# 测试代码...
2.7.1. 性能对比(10 个 I/O 任务)
方式 |
时间 |
说明 |
|---|---|---|
串行 |
~10s |
一个接一个 |
多线程 |
~1s |
并发执行 |
多进程 |
~1s |
并行执行(资源开销大) |
asyncio |
~1s |
并发执行(最轻量) |
2.7.2. 性能对比(CPU 密集型任务)
方式 |
时间 |
说明 |
|---|---|---|
串行 |
基准 |
- |
多线程 |
≈ 基准 |
GIL 限制 |
多进程 |
基准/核心数 |
真正并行 |
asyncio |
≈ 基准 |
不适合 CPU 密集 |
2.8. 本章重点
GIL 深度解析
理解全局解释器锁的原理和影响,知道何时它是问题,何时不是。
多线程编程
线程同步、锁、条件变量,以及如何避免死锁和竞态条件。
多进程编程
进程间通信、共享状态、进程池的正确使用。
asyncio 异步编程
协程、事件循环、异步上下文,构建高性能异步应用。
2.9. 选型指南
graph TD
A[任务类型?] --> B{I/O 密集型}
A --> C{CPU 密集型}
A --> D{混合型}
B --> E{需要高并发?}
E -->|是| F[asyncio]
E -->|否| G[threading]
C --> H{可以用 NumPy?}
H -->|是| I[NumPy 已释放 GIL]
H -->|否| J[multiprocessing]
D --> K[分离 I/O 和 CPU<br>分别处理]