添加concurrent.futures 中的ThreadPoolExecutor,为什么选择多线程而不是多进程

  1. 内存开销 (Memory Footprint) —— 最核心的理由
    多进程 (Multiprocessing):Python 的多进程是非常“重”的。每启动一个子进程,Python 实际上会 fork 一个全新的解释器环境,并复制父进程的内存空间(虽然有 Copy-on-Write,但基础开销依然很大)。

场景推演:假设你要并发跑 50 台设备。

如果用 ProcessPoolExecutor:你需要启动 50 个 Python 解释器进程。假设一个空 Python 进程占 20MB 内存,光调度器本身就吃了 1GB (50 * 20MB) 内存!这还是没算业务逻辑的情况。

多线程 (Threading):线程是轻量级的,50 个线程共享同一个 Python 解释器进程的堆内存。

场景推演:50 个线程加起来,可能只比单进程多占几十 MB 的栈空间。对于资源受限的 CI 服务器(比如 Jenkins Agent),省下的这 1GB 内存可以多跑好几个 Docker 容器。

  1. 上下文切换成本 (Context Switching)
    进程切换:操作系统调度进程时,需要切换页表(Page Table)、刷新 TLB(快表),开销很大。

线程切换:都在同一个进程空间内,只切换寄存器和栈,开销极小。

结论:既然我们的 Python 脚本只是个“监工”(Supervisor),大部分时间在 sleep,用昂贵的进程切换来管理它是杀鸡用牛刀。

  1. 通信复杂度 (IPC vs Shared Memory)
    还记得你写的 self.results.append(result) 吗?

多线程:因为共享内存,你可以直接 append 到列表里(只要加个轻量级的 Lock)。

多进程:进程间内存隔离。你不能直接 append!你需要使用 multiprocessing.Queue、Pipe 或者 Manager 来做进程间通信 (IPC)。这不仅代码写起来极其麻烦,而且数据序列化/反序列化(Pickle)也会消耗 CPU。

posted @ 2026-02-03 06:40  CalvinMax  阅读(4)  评论(0)    收藏  举报