【问题标题】:Share a list between different processes?在不同进程之间共享列表?
【发布时间】:2021-04-30 05:49:53
【问题描述】:

我有以下问题。我编写了一个函数,它接受一个列表作为输入,并为列表中的每个元素创建一个字典。然后我想将此字典附加到一个新列表中,因此我得到了一个字典列表。我正在尝试为此产生多个进程。我的问题是我希望不同的进程访问字典列表,因为它被其他进程更新,例如,一旦达到一定长度就打印一些东西。

我的例子是这样的:

import multiprocessing

list=['A', 'B', 'C', 'D', 'E', 'F']

def do_stuff(element):
    element_dict={}
    element_dict['name']=element
    new_list=[]
    new_list.append(element_dict)
    if len(new_list)>3:
        print 'list > 3'

###Main###
pool=multiprocessing.Pool(processes=6)
pool.map(do_stuff, list)
pool.close()

现在我的问题是每个进程都创建了自己的new_list。有没有办法在进程之间共享列表,以便所有字典都附加到同一个列表中?或者是在函数之外定义new_list 的唯一方法?

【问题讨论】:

标签: python list multiprocessing


【解决方案1】:

win10可以运行

import multiprocessing

list=['A', 'B', 'C', 'D', 'E', 'F']

def do_stuff(element,sharedlist):
    element_dict={}
    element_dict['name']=element
    sharedlist.append(element_dict)
    print(sharedlist)



if __name__ == "__main__":
    pool=multiprocessing.Pool(processes=6)
    manager=multiprocessing.Manager()
    sharedlist=manager.list()
    tasks = [(x,sharedlist) for x in list]
    pool.starmap(do_stuff, tasks)
    pool.close()

【讨论】:

    【解决方案2】:

    以下来自python documentation

    from multiprocessing import shared_memory
    a = shared_memory.ShareableList(['howdy', b'HoWdY', -273.154, 100, None, True, 42])
    [ type(entry) for entry in a ]
    [<class 'str'>, <class 'bytes'>, <class 'float'>, <class 'int'>, <class 'NoneType'>, <class 'bool'>, <class 'int'>]
    a[2]
    -273.154
    a[2] = -78.5
    a[2]
    -78.5
    a[2] = 'dry ice'  # Changing data types is supported as well
    a[2]
    'dry ice'
    a[2] = 'larger than previously allocated storage space'
    Traceback (most recent call last):
      ...
    ValueError: exceeds available storage for existing str
    a[2]
    'dry ice'
    len(a)
    7
    a.index(42)
    6
    a.count(b'howdy')
    0
    a.count(b'HoWdY')
    1
    a.shm.close()
    a.shm.unlink()
    del a  # Use of a ShareableList after call to unlink() is unsupported
    

    【讨论】:

    • 请考虑使用提供的空间来详细说明您的答案有效的原因。
    【解决方案3】:

    一种方法是使用管理器对象并从中创建您的共享列表对象:

    from multiprocessing import Manager, Pool
    
    input_list = ['A', 'B', 'C', 'D', 'E', 'F']
    
    manager = Manager()
    shared_list = manager.list()
    
    def do_stuff(element):
        global shared_list
        element_dict = {}
        element_dict['name'] = element
        shared_list.append(element_dict)
        if len(shared_list) > 3:
            print('list > 3')
    
    pool = Pool(processes=6)
    pool.map(do_stuff, input_list)
    pool.close()
    

    请记住,与线程不同,进程不共享内存空间。 (当产生时,每个进程都会获得它自己的产生过程的内存占用的副本,然后与它一起运行。)因此它们只能通过某种形式的 IPC(进程间通信)进行通信。在 Python 中,一种这样的方法是 multiprocessing.Manager 及其公开的数据结构,例如listdict。它们在代码中的使用与它们的内置等效项一样容易,但在后台使用某种形式的 IPC(可能是套接字)。

    【讨论】:

    • 谢谢!我已经尝试放入一个管理器对象,但并没有真正让它工作......
    • 这在 Windows 上不起作用,因为每个进程都有自己的shared_list,因此不会共享列表。这也是某种“分叉炸弹”,因为每个进程都会创建自己的 Pool 并启动 6 个其他进程,这些进程也创建自己的 Pool 对象并启动 6 个其他进程,这些进程也......
    • global 无论如何都是一个坏主意,但在这里它确实是错误的。 shared_listpool 需要在函数中是本地的,必须保护该函数仅在主程序中调用而不是在导入模块时调用,并且必须将列表作为参数提供给 do_stuff()
    猜你喜欢
    • 2011-01-30
    • 2021-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-03
    • 2022-01-16
    • 2012-07-22
    相关资源
    最近更新 更多