多处理池中的全局变量

Posted

技术标签:

【中文标题】多处理池中的全局变量【英文标题】:Global Variable in Multiprocessing Pool 【发布时间】:2021-07-22 19:06:06 【问题描述】:

我知道这个问题之前已经在这里讨论过,但是我找不到任何有效的方法。 我想在我的多处理进程之间共享一个全局变量,而不需要任何进程更改它,即它们只需要读取访问权限。举个简单的例子:

    def f(x):
        return x**GlobalVar

    if __name__ == '__main__':
        GlobalVar = 6
        pool = multiprocessing.Pool()
        res= pool.map(f,[1,2,3,4])
        print(res)

现在这显然不起作用,因为进程无法访问 GlobalVar。因此,为了让它工作,我会在每个单独的过程中评估 GlobalVar,或者从文件中导入它。由于在我的应用程序中 GlobalVar 是一个非常大的数组,这非常浪费。如何在进程之间轻松共享此全局变量,同时将其副本存储在内存中?我想重申一下,进程只需要读取这个全局变量而不改变它。

【问题讨论】:

如果相关,我正在运行 Windows... 【参考方案1】:

非常简单的方法是将其作为参数传递给在每个进程中执行的f。但是如果全局变量太大,你不想在每个进程中都有一份它的副本,而你只打算执行读取操作,那么你可以使用共享内存。

示例(内嵌文档)

from multiprocessing import Pool
from multiprocessing import shared_memory
import numpy as np
def f(x):
    # Attach to the existing shared memory
    existing_shm = shared_memory.SharedMemory(name='abc123')
    # Read from the shared memory (we know the size is 1)
    c = np.ndarray((1,), dtype=np.int64, buffer=existing_shm.buf)
    return x*c[0]

if __name__ == '__main__':
    a = np.array([6])
    # Creates shared memory with name abc123
    shm = shared_memory.SharedMemory(create=True, size=a.nbytes, name="abc123")
    # Create numpy array backed by shared memory
    b = np.ndarray(a.shape, dtype=a.dtype, buffer=shm.buf)
    # copy the data into shared memory
    b[:] = a[:]
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))

输出:

[6, 12, 18]

查找官方文档here。

【讨论】:

【参考方案2】:

由于您希望共享的变量是只读的并且是一个“简单”整数,您只需通过在全局范围内声明它来使其对多处理池中的子进程可见:

import multiprocessing

GlobalVar = 6

def f(x):
    return x**GlobalVar

if __name__ == '__main__':
    pool = multiprocessing.Pool()
    res= pool.map(f,[1,2,3,4])
    print(res)

打印:

[1, 64, 729, 4096]

讨论

在讨论 Python 和多处理时,您在哪个平台上运行总是相关的,我已经更新了您的标签以添加 Windows(尽管)现在编写的代码也可以在 Linux 上运行。

在 Windows 上,当创建新进程(或创建进程池时的进程)时,使用 spawn。这意味着新进程不会继承主进程建立的变量,而是为每个新进程启动一个新的 Python 解释器,并从程序顶部开始执行。这就是为什么您必须将启动新进程的代码包含在 if __name__ == '__main__': 块中,否则您将进入递归循环。但是出于这个原因,您必须将GlobalVar 的声明移动到全局范围,否则将不会为新创建的进程定义该变量。

为池中的每个子进程初始化全局变量的另一种方法是使用池初始化函数,它使您能够做比这演示的更复杂的事情:

import multiprocessing

def init_pool(the_int):
    global GlobalVar
    GlobalVar = the_int

def f(x):
    return x**GlobalVar

if __name__ == '__main__':
    GlobalVar = 6
    pool = multiprocessing.Pool(initializer=init_pool, initargs=(GlobalVar,))
    res= pool.map(f,[1,2,3,4])
    print(res)

【讨论】:

以上是关于多处理池中的全局变量的主要内容,如果未能解决你的问题,请参考以下文章

父进程全局变量如何复制到python多处理中的子进程

python中的多处理模块和修改共享的全局变量

为啥多处理工作者不能更改全局变量? [复制]

python多处理是否通过全局标志变量安全地进行进程间信令?

python多处理子进程无法访问全局变量

多处理全局变量更新未返回给父级