多进程池中的全局变量

3

我知道这个问题以前已经在这里讨论过,但我就是找不到任何可行的方法。我想在我的多进程之间共享一个全局变量,但不希望任何一个进程修改它,也就是说,它们只需要读取权限。举个简单的例子:

    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... - Randomgenerator
2个回答

3

一种非常简单的方法是将其作为参数传递给每个进程中执行的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]

官方文档在这里


3

如果您希望共享的变量是只读的“简单”整数,并且需要在多进程池中使其可见,那么您只需在全局范围内声明它即可:

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)

第二个脚本不起作用,我遇到了 UnboundLocalError: local variable 'GlobalVar' referenced before assignment - Tropilio
@Tropilio 那么你没有完全运行上面的代码。请参见使用上述确切源代码的演示 - Booboo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接