multiprocessing.Pipe()返回的连接对象是否在不同进程间共享?
现象本质解释
你观察到的主进程和sender子进程中打印的连接对象地址不同,是多进程模型下的正常表现,既不存在两个独立管道,也不是因为进程间不共享内存导致的通信失效。
- 主进程中通过
multiprocessing.Pipe()创建的管道,本质是操作系统内核维护的一块带读写缓冲区的通信对象,每个管道连接在用户态的Python层会被封装成一个Connection类实例,这个实例内部会记录内核管道对应的文件描述符(fd)。 - 当通过
Process启动子进程并传递连接对象时,multiprocessing框架会将连接对象序列化,通过操作系统提供的跨进程文件描述符传递机制,把内核管道的引用映射到子进程的文件描述符表中;子进程反序列化得到的conn是一个全新的Python对象,因此内存地址和主进程中的parent_conn必然不同。 - 两个进程中的连接对象只是用户态的独立副本,底层指向的是内核中同一个管道实例,不会因为Python对象的独立存在就生成两套独立的管道。
疑问解答
疑问1:为什么子进程中形参的通信操作能和主进程的管道联通?
跨进程的管道通信逻辑完全在内核层实现,和用户态的Python对象内存位置没有关系。
你在子进程中调用conn.send()时,实际是通过自己进程内映射的文件描述符,把数据写入内核的管道缓冲区;主进程中的parent_conn只要还持有同一个管道的有效文件描述符,就可以直接从这个内核缓冲区读取数据。这套机制和你在两个终端进程中打开同一个本地文件,一个进程写入内容、另一个进程能读到的逻辑完全一致,和Python层面是否共享变量、对象地址是否相同没有关联。
疑问2:为什么子进程中执行conn.close()后,主进程的parent_conn.closed仍为False?
Connection对象的closed属性,是当前进程内Python实例自己的状态标记,不是内核管道的全局状态。
- 子进程中执行
conn.close()时,只会修改子进程内部这个Python连接对象的关闭标记,同时把当前进程文件描述符表中映射到该管道的fd释放,减少内核管道对象的引用计数。 - 主进程中的
parent_conn是独立的Python实例,它自身的状态标记完全由主进程内的操作控制,不会被子进程的状态修改;同时主进程的文件描述符表中还持有该管道的有效fd,因此parent_conn.closed会一直保持False。
内核层面的管道销毁,只有在所有进程持有的对应fd都被close、管道引用计数归零后才会触发,单靠某一个进程内的连接关闭,不会影响其他进程中连接对象的状态。
内容的提问来源于stack exchange,提问作者lanling
相关产品推荐
相关产品推荐

