Python多处理——共享id的单独进程中的全局变量?

Yib*_*ang 4 python parallel-processing multiprocessing python-multiprocessing

这个问题我了解到:

当您使用多处理打开第二个进程时,会创建一个全新的 Python 实例,具有自己的全局状态。该全局状态不共享,因此子进程对全局变量所做的更改对于父进程来说是不可见的。

为了验证这种行为,我制作了一个测试脚本:

import time
import multiprocessing as mp
from multiprocessing import Pool
x = [0]  # global
def worker(c):
    if c == 1:  # wait for proc 2 to finish; is global x overwritten by now?
        time.sleep(2)
    print('enter: x =', x, 'with id', id(x), 'in proc', mp.current_process())
    x[0] = c
    print('exit: x =', x, 'with id', id(x), 'in proc', mp.current_process())
    return x[0]

pool = Pool(processes=2)
x_vals = pool.map(worker, [1, 2])
print('parent: x =', x, 'with id', id(x), 'in proc', mp.current_process())
print('final output', x_vals)
Run Code Online (Sandbox Code Playgroud)

输出(在 CPython 上)类似于

enter: x = [0] with id 140138406834504 in proc <ForkProcess(ForkPoolWorker-2, started daemon)>
exit: x = [2] with id 140138406834504 in proc <ForkProcess(ForkPoolWorker-2, started daemon)>
enter: x = [0] with id 140138406834504 in proc <ForkProcess(ForkPoolWorker-1, started daemon)>
exit: x = [1] with id 140138406834504 in proc <ForkProcess(ForkPoolWorker-1, started daemon)>
parent: x = [0] with id 140138406834504 in proc <_MainProcess(MainProcess, started)>
final output [1, 2]
Run Code Online (Sandbox Code Playgroud)

id我该如何解释ofx在所有进程中共享,但x取不同值的事实?从概念上讲,这不是idPython对象的内存地址吗?我想如果内存空间在子进程中被克隆,这是可能的。那么有什么东西可以用来获取Python对象的实际物理内存地址吗?

Dar*_*aut 5

共享状态

当您使用多处理打开第二个进程时,会创建一个全新的 Python 实例,具有自己的全局状态。该全局状态不共享,因此子进程对全局变量所做的更改对于父进程来说是不可见的。

这里的关键点似乎是:

这个全球状态不是共享的……”

...指的子进程的全局状态。但这并不意味着父进程的部分全局状态不能与子进程共享,只要子进程不尝试写入部分即可。当这种情况发生时,部分将被复制和更改,并且对父级不可见。

背景:

在 Unix 上,“fork”是启动子进程的默认方式:

父进程使用 os.fork() 来 fork Python 解释器。子进程在启动时实际上与父进程相同。父进程的所有资源都被子进程继承。请注意,安全分叉多线程进程是有问题的。

仅适用于 Unix。Unix 上的默认值。

Fork 是使用copy-on-write实现的,因此除非您分配一个新对象,否则x不会发生复制,并且子进程与其父进程共享相同的列表。


内存地址

我该如何解释 x 的 id 在所有进程中共享,但 x 取不同值的事实?

Fork 创建一个子进程,其中的虚拟地址空间与父进程的虚拟地址空间相同。虚拟地址将全部映射到相同的物理地址,直到发生写时复制。

现代操作系统使用虚拟寻址。基本上,您在程序中看到的地址值(指针)不是实际的物理内存位置,而是指向索引表(虚拟地址)的指针,而索引表又包含指向实际物理内存位置的指针。由于这种间接性,如果虚拟地址属于不同进程的索引表,则可以使相同的虚拟地址指向不同的物理地址。关联


那么有什么东西可以用来获取Python对象的实际物理内存地址吗?

There doesn't seem to be a way to get the actual physical memory address (link). id returns the virtual (logical) memory address (CPython). The actual translation from virtual to physical memory address falls to the MMU.