python多进程派生如何在资源共享方面工作

时间:2019-06-28 19:00:58

标签: python python-3.x multiprocessing

import multiprocessing as mp
class Job:
    def __init__(self,name):
        self.name=name
class A:
    def __init__(self,x):
        self.x=x
    def run(self,job):
        self.x+=1
        print(id(self.x),self.x,job.name)

    def mul_process_test(self):
        j1=Job('hello')
        j2=Job('world')
        p1=mp.Process(target=self.run,args=(j1,))
        p2=mp.Process(target=self.run,args=(j2,))
        p1.start()
        p2.start()
        p1.join()
        p2.join()
if __name__ =='__main__':
    a=A(1)
    a.mul_process_test()
    print(id(a.x),a.x)

以上代码的结果为:

10919360 2 hello
10919360 2 world
10919328 1

似乎两个进程中的self.x具有相同的ID,10919360(这对我来说没有意义),但与主进程具有不同的ID(对我来说却有意义)。 我在Linux中使用python3.5,如文档所述,默认的start方法采用类似fork的方式来启动新进程。我想知道两个过程中self.x的ID为什么相同。

三个进程(主进程和两个以mp.Process开头的进程)之间是否共享任何内容?

1 个答案:

答案 0 :(得分:3)

CPython(Python参考解释器)中的

id s只是内存地址。 CPython(作为实现的详细信息)使用小的int缓存,因此从-5到256的所有数字都是单例。因此,您的子进程会从父进程复制相同的虚拟地址表,并继承相同的小型int缓存。当他们计算self.x += 1时,他们会查找相同的2缓存值。

现在,从技术上讲,由于使用CPython参考计数,2的每个进程所基于的物理RAM将不再相同(参考计数更新将迫使写页面上的副本尽快复制到子页面中)因为参考了这些值,所以增加了参考计数)。但是写时复制语义保留了虚拟内存地址,它们只是重新映射了底层物理页面,而CPython的id正在报告(未更改的)虚拟内存地址。因此,对于介于-5到256之间的任何值,在id版的子进程中,fork的期望是相同的。您只会期望超出该范围的值会有差异,即使这样,如果运行时行为相同(可能也会在fork上复制分配器状态;直到某些差异或不确定性会改变分配模式,分配的内存地址将继续遵循相同的模式。