在Python multiprocessing.Pool中共享可变全局变量

在Python multiprocessing.Pool中共享可变全局变量,python,python-3.x,multiprocessing,python-multiprocessing,multiprocessing-manager,Python,Python 3.x,Multiprocessing,Python Multiprocessing,Multiprocessing Manager,我正在尝试使用以下代码更新共享对象(dict)。但它不起作用。它将输入dict作为输出 编辑:显然,我在这里试图实现的是将数据(列表)中的项目附加到dict列表中。数据项在目录中给出索引 预期输出:{'2':[2],'1':[1,4,6],'3':[3,5]} 注意:方法2引发错误TypeError:“int”对象不可编辑 方法1 from multiprocessing import * def mapTo(d,tree): for idx, item in enumerate

我正在尝试使用以下代码更新共享对象(dict)。但它不起作用。它将输入
dict
作为输出

编辑:显然,我在这里试图实现的是将数据(列表)中的项目附加到dict列表中。数据项在目录中给出索引

预期输出
{'2':[2],'1':[1,4,6],'3':[3,5]}

注意:方法2引发错误
TypeError:“int”对象不可编辑

  • 方法1

    from multiprocessing import *
    def mapTo(d,tree):
            for idx, item in enumerate(list(d), start=1):
                tree[str(item)].append(idx)
    
    data=[1,2,3,1,3,1]
    manager = Manager()
    sharedtree= manager.dict({"1":[],"2":[],"3":[]})
    with Pool(processes=3) as pool:
        pool.starmap(mapTo, [(data,sharedtree ) for _ in range(3)])
    
  • 方法2

  • 如果希望反映更改,则需要使用托管列表。因此,以下内容对我很有用:

    from multiprocessing import *
    def mapTo(d,tree):
            for idx, item in enumerate(list(d), start=1):
                tree[str(item)].append(idx)
    
    if __name__ == '__main__':
        data=[1,2,3,1,3,1]
    
        with Pool(processes=3) as pool:
            manager = Manager()
            sharedtree= manager.dict({"1":manager.list(), "2":manager.list(),"3":manager.list()})
            pool.starmap(mapTo, [(data,sharedtree ) for _ in range(3)])
    
        print({k:list(v) for k,v in sharedtree.items()})
    
    这是输出:

    {'1': [1, 1, 1, 4, 4, 4, 6, 6, 6], '2': [2, 2, 2], '3': [3, 3, 5, 3, 5, 5]}
    
    注意,在使用多处理时,您应该始终使用
    if\uuuuuuu name\uuuuuu='\uuuuu main\uuuuuu':
    保护,同时,避免带星号的导入

    编辑 如果您使用的是Python<3.6,则必须执行此重新分配,因此请将其用于
    mapTo

    def mapTo(d,tree):
            for idx, item in enumerate(list(d), start=1):
                l = tree[str(item)]
                l.append(idx)
                tree[str(item)] = l
    
    最后,如果没有正确使用
    星图
    /
    星图
    ,则会将数据传递三次,因此,所有数据都会被计算三次。映射操作应适用于要映射的数据的每个单独元素,因此您需要以下内容:

    from functools import partial
    from multiprocessing import *
    def mapTo(i_d,tree):
        idx,item = i_d
        l = tree[str(item)]
        l.append(idx)
        tree[str(item)] = l
    
    if __name__ == '__main__':
        data=[1,2,3,1,3,1]
    
        with Pool(processes=3) as pool:
            manager = Manager()
            sharedtree= manager.dict({"1":manager.list(), "2":manager.list(),"3":manager.list()})
            pool.map(partial(mapTo, tree=sharedtree), list(enumerate(data, start=1)))
    
        print({k:list(v) for k,v in sharedtree.items()})
    

    与其在进程之间共享dict是个坏主意,不如从每个进程返回一个dict,然后合并它们。为什么共享dict是个坏主意?在我的例子中,dict是一种哈希表,它非常大,我认为返回dict是没有意义的。而且,所有进程都应该在dict的列表中附加项目。我不担心竞争条件,因为
    管理器的列表可以由子进程独立更新。在不同进程之间共享数据结构有点棘手。这当然可以做到,但对于@JoshuaNixon point,请确保没有更简单的方法来完成手头的任务。方法2会引发错误,因为它调用
    mapTo
    ,并且在每次调用中都会从您的代码中传递一个单独的listo/p元素,即
    {2':[],'1':[],'3':[]}
    @chandresh I无法重现。我得到上面的输出。你确定你正在运行这个代码吗?是的。我复制粘贴了您的代码并在spyder中使用py 3.5运行。此外,如顶部问题所示,您的o/p不是我预期的o/p。@chandresh是的,这是因为您不正确地使用了
    pool.map
    。但这与你的问题无关。问题是,您无法在Python3.5中轻松嵌套托管对象,您必须执行看似冗余的重新分配。你真的应该升级…嗯。在py 3.5中,dict列表的赋值似乎是3行代码。
    from functools import partial
    from multiprocessing import *
    def mapTo(i_d,tree):
        idx,item = i_d
        l = tree[str(item)]
        l.append(idx)
        tree[str(item)] = l
    
    if __name__ == '__main__':
        data=[1,2,3,1,3,1]
    
        with Pool(processes=3) as pool:
            manager = Manager()
            sharedtree= manager.dict({"1":manager.list(), "2":manager.list(),"3":manager.list()})
            pool.map(partial(mapTo, tree=sharedtree), list(enumerate(data, start=1)))
    
        print({k:list(v) for k,v in sharedtree.items()})