← 返回题目列表

Python 多进程之间如何通信?Queue、Pipe、Manager 和 shared_memory 有什么区别?

高频 困难 第 14 / 27 题 更新于 2026/07/27
multiprocessing进程通信QueuePipeshared_memory

简化版

多进程默认内存隔离,不能像线程那样直接共享普通变量。常见通信方式有 multiprocessing.Queue 传消息,Pipe 做两个端点通信,Manager 提供代理对象,shared_memory 用于共享大块内存。一般任务分发优先 Queue,大数据共享才考虑 shared memory。

详细版

对比:

方式特点适合场景
Queue多生产者多消费者消息队列任务分发、结果回传
Pipe两端连接,点对点通信父子进程简单对话
Manager通过代理共享 list、dict 等对象简单共享状态,性能要求不高
shared_memory共享原始内存块大数组、大块二进制数据

Queue 示例:

from multiprocessing import Process, Queue

def worker(q):
    q.put("done")

if __name__ == "__main__":
    q = Queue()
    p = Process(target=worker, args=(q,))
    p.start()
    print(q.get())
    p.join()

注意点:

  • 跨进程传递对象通常涉及序列化;
  • 不要频繁传超大对象;
  • Manager 简单但开销较大;
  • shared memory 性能更好,但需要自己管理结构和同步;
  • 进程退出时要注意资源释放。

完整版教学

一、多进程为什么需要专门通信机制

线程共享同一进程内存,所以可以直接访问同一个对象。进程不同,每个进程通常有独立地址空间:

进程 A 的变量 x 和进程 B 的变量 x 不是同一个内存位置

这带来隔离性,也带来通信成本。要让进程协作,就必须使用 IPC,也就是进程间通信机制。

二、Queue 是最常用的任务通道

multiprocessing.Queue 的使用体验和线程队列类似,但用于进程之间:

from multiprocessing import Process, Queue

def producer(q):
    for i in range(5):
        q.put(i)
    q.put(None)

def consumer(q):
    while True:
        item = q.get()
        if item is None:
            break
        print(item)

它适合:

  • 父进程给子进程派任务;
  • 子进程把结果返回父进程;
  • 多个 worker 之间传递简单消息。

但传入 Queue 的对象通常要序列化,所以不要频繁传巨大的 DataFrame、图片数组或模型对象。

三、Pipe 更像一根双向管道

Pipe 返回两个连接端:

from multiprocessing import Pipe

parent_conn, child_conn = Pipe()

它适合两个进程之间点对点通信。相比 Queue,它语义更轻,但不如 Queue 适合多生产者多消费者模型。

如果通信拓扑简单,比如父进程发命令、子进程回结果,Pipe 可以很直观。

四、Manager 简单但不适合高性能

Manager 可以创建看起来像共享的字典、列表:

from multiprocessing import Manager

with Manager() as manager:
    shared_dict = manager.dict()

但这些对象通常是代理,操作会经过管理进程协调,不是普通内存直接访问。它方便,但慢。

适合:

  • 少量共享状态;
  • 原型代码;
  • 管理配置、状态标记。

不适合高频读写、大数据传输和性能敏感路径。

五、shared_memory 用于共享大块数据

如果多个进程要处理同一大块数组,复制成本很高,可以考虑共享内存。共享内存让多个进程访问同一块底层内存,减少复制。

但它更底层:

  • 需要自己定义数据结构;
  • 要管理生命周期;
  • 要处理同步;
  • 更容易出资源泄漏或数据竞争。

所以面试时可以说:普通任务通信优先 Queue,性能瓶颈明确且数据很大时才考虑 shared memory。

六、进程通信的设计原则

实践中有几个原则:

  1. 传小消息,不传大对象;
  2. 能让 worker 自己加载资源,就不要每次传资源;
  3. 明确结束信号;
  4. 主进程负责收集结果和异常;
  5. 对共享内存和 Manager 状态加同步保护。

这比单纯背 API 更重要。

七、常见误区与追问

方式适合场景主要代价
Queue多生产者多消费者任务流数据需要序列化和跨进程传输
Pipe两端点直接通信拓扑简单,扩展性弱
Manager共享字典、列表等代理对象代理进程转发,性能较低
shared_memory大数组、大块字节共享需要自己管理生命周期和同步
  • 误区:多进程之间能像多线程一样直接共享变量。 进程默认地址空间隔离,普通全局变量在不同进程里是各自副本,不是同一个对象。
  • 误区:Manager 对象和普通 dict/list 性能一样。 Manager 通过代理进程协调访问,方便但有 IPC 开销,不适合高频小操作。
  • 误区:shared_memory 共享了数据就不需要同步。 它只共享内存块,不自动保护读写顺序;多个进程同时写仍需要锁、队列或协议约束。
  • 追问:Queue 和 Pipe 怎么选? 多生产者多消费者、任务分发用 Queue 更自然;固定两个端点点对点通信可用 Pipe
  • 追问:为什么进程通信常要求对象可序列化? 因为跨进程传递通常要把对象编码成字节再发送到另一端,不能序列化的对象无法安全复制过去。
  • 追问:大数据传输为什么不总用 Queue? 大数组反复序列化和复制成本很高,shared_memory 可以减少复制,但要额外处理同步和释放。

记忆钩子:进程通信先问“传消息、共享代理,还是共享大块内存”,不要把所有问题都塞进 Manager

八、加强记忆

多进程默认不共享普通内存,所以要靠 IPC 协作。Queue 是最通用的消息通道,Pipe 是点对点管道,Manager 是方便但偏慢的代理共享状态,shared_memory 是高性能但更底层的大数据共享方案。先用 Queue,真遇到大对象复制瓶颈再升级。