Python 并发模型总览
分清并发与并行、I/O 密集与 CPU 密集;在线程、进程与 asyncio 之间做负载匹配选型。
#type / concept
#status / growing
#tech / dev
#resource / python
#tech / lang / python
[!info] 关联笔记
Python 并发模型总览
这个概念为什么出现
“慢”有不同原因:等网络,或算矩阵。用错模型会:
- 在 GIL 下徒增线程却不加速 CPU
- 用 asyncio 包一层仍调用阻塞 SDK
- 用多进程处理简单 I/O 却付出序列化成本
[!abstract] 一句话理解 先判断瓶颈是 I/O 还是 CPU,再在线程/进程/asyncio 中选择;并发结构解决重叠等待,并行结构解决多核计算。
最小可运行示例
先把示例放进业务场景,再看代码:
场景:运维脚本给三类任务贴标签选型
# concurrency_choose.py
# 业务意图:根据任务画像输出推荐模型(教学用规则)。
# 教学点:
# - I/O vs CPU;
# - 模型不是银弹;
# - 决策先分类。
def recommend(kind: str) -> str:
table = {
"many_http": "asyncio or thread pool",
"blocking_sdk": "thread pool / to_thread",
"cpu_hash": "process pool / native ext",
"simple_script": "sync first",
}
return table[kind]
def main() -> None:
for k in ["many_http", "blocking_sdk", "cpu_hash", "simple_script"]:
print(f"{k} -> {recommend(k)}")
if __name__ == "__main__":
main()
建议运行:
python concurrency_choose.py
期望输出:
many_http -> asyncio or thread pool
blocking_sdk -> thread pool / to_thread
cpu_hash -> process pool / native ext
simple_script -> sync first
结合场景再看三个关注点
- 先测量再并发——同步正确实现优先。
- 阻塞 SDK 不会因为函数写成 async 就变非阻塞。
- CPU 看多进程或下沉扩展。
核心概念与准确模型
| 模型 | 擅长 | 成本 |
|---|---|---|
| 多线程 | 阻塞 I/O 并发 | GIL 限 CPU;共享内存要同步 |
| 多进程 | CPU 并行 | 内存/序列化/启动 |
| asyncio | 高并发 I/O | 生态需异步化;禁阻塞 |
| 同步 | 简单正确 | 吞吐上限 |
边界情况与反直觉行为
- 混合负载需要分阶段/分池。
- GIL 在 I/O 或部分 C 扩展中会释放。
- 容器 CPU 限额改变“多进程收益”。
常见误区
[!warning] 常见误区:并发 = 多线程 错误理解:只有一种手段。
正确模型:多模型并存,按负载选型。
工程实践
- 统一超时、取消、背压
- 线程/进程池设上限
- 观测队列长度与延迟
本节总结
选型图比 API 背诵重要。后续三篇分别深入线程/GIL、进程与 asyncio 细节。
自测题
- 为何 CPU 密集不优先 asyncio?
- 阻塞 SDK 在异步服务中怎么放?
参考答案
- 事件循环通常单线程,算满会卡住所有任务。
- 丢到线程池/
to_thread,或换异步库。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| concurrent.futures | 文档 | 线程/进程池 |
| asyncio | 文档 | 异步 |