Python中具有只读共享内存的多处理程序?

问题描述 投票:0回答:2

我有一个单线程的Python程序,我想对其进行修改以利用运行它的服务器上的所有32个处理器。正如我所设想的,每个工作进程将从队列中接收其作业,并将其输出提交到队列。但是,为了完成其工作,每个工作进程都需要对复杂的内存中数据结构(相互链接的数十亿字节的字典和对象)进行只读访问。在python中,是否有一种简单的方法可以共享此数据结构,而无需为每个工作进程复制该数据结构?

谢谢。

python multithreading multiprocessing shared-memory
2个回答
9
投票

如果使用的是Python的CPython(或PyPy)实现,则global interpreter lock (GIL)将阻止一次在一个Python对象上运行多个线程。

因此,如果您使用的是这种实现,则需要使用多个进程而不是多个线程来利用32个处理器。

您可以使用标准库的multiprocessingconcurrent.futures模块来生成工作进程。也有many third-party optionsDoug Hellman's tutorial是对多处理模块的出色介绍。

由于只需要对数据结构的只读访问权限,如果将复杂的数据结构分配给全局变量之前,则生成进程,然后所有进程都可以访问此全局变量。

生成进程时,将来自调用模块的全局变量复制到生成的进程。但是,在具有copy-on-write的Linux上,产生的进程使用完全相同的数据结构,因此不需要额外的内存。仅当进程modified数据结构被复制到新位置时。

在Windows上,因为没有fork,所以每个生成的进程都会调用python并重新导入调用模块,因此每个进程都需要内存来存储其自己的庞大数据结构的单独副本。在Windows上必须有其他共享数据结构的方法,但是我不知道细节。 (编辑:POSH may be a solution to the shared-memory problem,但我自己还没有尝试过。)


0
投票

为了在上面添加对unutbu答案的演示,下面的代码表明它实际上是COW共享内存(CPython 3.6,Mac OS)

main_shared.py

import multiprocessing
from time import sleep


my_global = None


def test():
    global my_global
    read_only_secs = 3
    while read_only_secs > 0:
        sleep(1)
        print(f'child proc global: {my_global} at {hex(id(my_global))}')
        read_only_secs -= 1
    print('child proc writing to copy-on-write...')
    my_global = 'something else'
    while True:
        sleep(1)
        print(f'child proc global: {my_global} at {hex(id(my_global))}')


def set_func():
    global my_global
    my_global = [{'hi': 1, 'bye': 'foo'}]

if __name__ == "__main__":
    print(f'main proc global: {my_global} at {hex(id(my_global))}')
    set_func()
    print(f'main proc global: {my_global} at {hex(id(my_global))}')
    p1 = multiprocessing.Process(target=test)
    p1.start()

    while True:
        sleep(1)
        print(f'main proc global: {my_global} at {hex(id(my_global))}')

输出

$ python main_shared.py 
main proc global: None at 0x101b509f8
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc writing to copy-on-write...
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: something else at 0x1022ea3b0
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: something else at 0x1022ea3b0
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
child proc global: something else at 0x1022ea3b0
main proc global: [{'hi': 1, 'bye': 'foo'}] at 0x102341708
© www.soinside.com 2019 - 2024. All rights reserved.