bigywater.tech
Python · 5

多进程通信:Queue、Pipe 和共享内存怎么选

测Queue传输1000万个float64、Pipe做2000次ping-pong、shared_memory零拷贝共享数组,看三种跨进程通信方式的代价差在哪。

0.19s
Queue传输80MB数组的耗时
17微秒
Pipe单次小消息往返的延迟
零拷贝
shared_memory做到的跨进程数据共享

做的事:三种方式,跨进程传/共享同一份数据

进程之间默认内存不共享,得靠的IPC机制传数据。

测试的三种方式1. multiprocessing.Queue:子进程put一个1000万元素的numpy数组,父进程get 2. multiprocessing.Pipe:两个进程做2000次一来一回的ping-pong 3. multiprocessing.shared_memory:子进程直接原地修改共享的numpy数组,父进程直接读

验证:Queue要为大数据付出序列化的代价

Queue底层是把对象pickle序列化后通过管道传输。

结果Queue传输1000万个float64(约80MB): 总耗时 0.1924s 接收方收到并sum: 49999995000000.0(数据完整无误)

Queue可以传任何可pickle的Python对象,很通用,但代价是:发送方要把整个对象序列化成字节流,接收方要再反序列化回来——80MB的数组花了0.19秒,这个耗时会随数据量线性增长。

验证:Pipe适合频繁的小消息往返

Pipe是两个进程之间一根直连的双向管道,延迟远低于Queue。

结果2000次ping-pong往返: 总耗时 0.0337s 平均单次往返: 16.9 微秒

对于小消息的高频往返,Pipe的单次延迟只有约17微秒——这类场景如果用Queue也能做,但Pipe是两个进程间专用的直连通道,没有Queue内部锁和缓冲队列那一层额外开销,更适合频繁的小数据交互(比如心跳、控制信号)。

验证:shared_memory做到了零拷贝

如果数据是numpy这类支持buffer协议的类型,共享内存能让两个进程"看见"同一块物理内存。

结果子进程原地把共享数组每个元素乘以2,耗时0.1034s(主要是进程启动开销,不是数据传输开销) 父进程直接读取子进程写入的结果(不需要任何显式发送): shm_arr[5] = 10.0 (期望值 5×2=10,吻合)

父进程完全没有执行任何"接收"操作——子进程原地改了共享内存里的数据,父进程直接读同一块内存就看到了变化。这是三种方式里唯一做到"零拷贝"的——不需要序列化、不需要通过管道搬运数据,两个进程共享的是同一块物理内存。代价是:只能用于支持这种内存布局的数据类型(定长的数值数组等),不像Queue那样能传任意Python对象。

三种方式的取舍:Queue最通用但大数据慢(要序列化);Pipe延迟最低适合小消息高频交互;shared_memory对大块数值数据最快(零拷贝),但只能用于buffer协议支持的类型,用起来也更复杂(要自己管理内存的创建和释放)。

分步演示:三种跨进程通信方式的代价对比

每一步都是本文上面用multiprocessing跑出来的原始结果。

Queue要序列化,Pipe延迟低,shared_memory零拷贝
这一步新验证的方式

    本文用到的工具

    • 本机 Python 3.14.7 + numpy 2.5.1
    • multiprocessing.Queue / Pipe / shared_memory.SharedMemory:对比三种IPC方式
    京ICP备2026067502号-1京公网安备11010502063487号