Python multiprocessing多进程对象地址相同及缓存继承问题
两个现象的具体成因解释
现象1:不同子进程中同类实例打印的内存地址完全一致
首先要明确:Python打印对象时输出的0xXXXX是进程虚拟地址空间内的逻辑地址,不是系统实际的物理内存地址,这个现象完全符合进程地址空间独立的特性:
- 每个进程拥有独立的虚拟地址空间,相同的逻辑地址在不同进程中会映射到完全不同的物理内存页,彼此完全隔离,修改其中一个进程的对象属性不会影响其他进程的同名对象
- Unix/Linux/macOS系统下,Python的
multiprocessing默认使用fork()系统调用创建子进程,fork()会完整复制父进程的虚拟地址空间布局、内存分配器状态,各个子进程从fork点开始执行时,内存分配的初始状态完全一致,你创建的是大小相同的小对象,所以分配到的虚拟地址偏移完全相同,最终打印出来的逻辑地址就会一致。
现象2:子进程继承主进程的类属性缓存数据
这个现象同样是fork()的特性导致的:
- 你代码中的
c是SomeOtherClass的类属性,属于进程全局的静态数据,存放在进程的数据段中 - 父进程是在
fork创建所有子进程之前,就已经完成了c字典的写入操作,fork()执行时,父进程的所有用户态内存数据(包括已经写入缓存的c字典)会以**写时复制(Copy-on-Write)**的方式继承给所有子进程 - 子进程刚启动时没有修改过
c字典,所以直接读取到了继承的缓存数据;如果子进程后续对c做修改操作,会触发写时复制机制,操作系统会为子进程复制一份独立的c字典,之后各进程的c就完全隔离,修改不会互相影响 - 补充说明:如果在Windows系统运行,或者手动指定
multiprocessing的启动方式为spawn,就不会出现该继承现象,因为spawn模式会重新启动独立的Python解释器进程,重新导入所有模块,类属性会回到初始空值状态。
内容的提问来源于stack exchange,提问作者Mario Kirov
相关产品推荐
相关产品推荐

