Python 并发编程入门:threading、multiprocessing 与 asyncio 的选型思路
为什么并发选型值得单独讲
很多初学者写并发代码的第一反应是“多开线程”,但 Python 的并发模型和其他语言不太一样:GIL(全局解释器锁)让同一时刻只有一个线程在执行字节码。选型错了,代码非但不会变快,还可能更慢、更难维护。这篇短文把最常用的三种并发方案按“任务类型”梳理一遍,帮助你在动手之前就选对方向。
三种方案各自的适用场景
threading(多线程):适合 I/O 密集型任务,比如批量请求接口、下载文件、读写数据库。线程在等待网络或磁盘时会把 GIL 让出来,因此这种“顺风等待”是可以叠加的。代价是要处理线程安全:共享数据要么加锁保护,要么改用队列通信。
multiprocessing(多进程):适合 CPU 密集型任务,比如图片处理、批量计算、数据清洗。每个进程拥有独立的解释器和内存空间,可以真正利用多核。代价是进程启动成本高、跨进程通信需要序列化,给子进程传大对象时要格外小心。
asyncio(协程):同样面向 I/O 密集型场景,但用单线程事件循环换来了极低的并发成本,成百上千个并发连接也不在话下,适合高并发网络服务和批量调度型爬虫。代价是必须停留在 async/await 生态里,一旦混入某个阻塞调用,整个事件循环都会被拖住。
一句话选型法则
- 瓶颈在“等外部”(网络、磁盘)→ 优先 asyncio,推荐用 threading 做后备;
- 瓶颈在“算内部”(CPU 计算)→ 直接 multiprocessing;
- 网络 I/O 且并发量非常大 → asyncio;
- 要复用现成的同步库、希望改动最小 → threading。
一个容易踩的坑
把 CPU 密集任务塞进多线程,测速后往往比串行还慢,原因正是 GIL:线程之间频繁切换,只增加了调度开销,没有换来并行计算。反过来,把一次性的网络请求放进多进程,启动十个解释器的时间可能比下载本身还长。动手前先问一句:我的瓶颈是在“等”,还是在“算”?这个问题想清楚,方案基本就唯一了。
小结
并发不是银弹。先看任务类型,再看并发规模,最后看生态兼容性——三步想清楚,选型不再靠猜。希望这篇入门短文能帮你避开最常见的两类弯路:算力白费和调度空转。
- 点赞
- 收藏
- 关注作者
评论(0)