分别在并行进程中改变不同的python对象
简而言之 我想同时更改复杂的python对象,这样每个对象只由一个进程处理。我如何才能做到这一点(最有效)?实施某种酸洗支持会有帮助吗?那会有效率吗 全部问题 我有一个python数据结构分别在并行进程中改变不同的python对象,python,fork,shared-memory,pickle,python-multiprocessing,Python,Fork,Shared Memory,Pickle,Python Multiprocessing,简而言之 我想同时更改复杂的python对象,这样每个对象只由一个进程处理。我如何才能做到这一点(最有效)?实施某种酸洗支持会有帮助吗?那会有效率吗 全部问题 我有一个python数据结构ArrayDict,它基本上由一个numpy数组和一个字典组成,并将任意索引映射到数组中的行。在我的例子中,所有键都是整数 a = ArrayDict() a[1234] = 12.5 a[10] = 3 print(a[1234]) #12.5
ArrayDict
,它基本上由一个numpy
数组和一个字典组成,并将任意索引映射到数组中的行。在我的例子中,所有键都是整数
a = ArrayDict()
a[1234] = 12.5
a[10] = 3
print(a[1234]) #12.5
print(a[10]) # 3.0
print(a[1234] == a.array[a.indexDict[1234]]) #true
现在我有多个这样的ArrayDict
s,我想把它们填入myMethod(ArrayDict,params)
。因为myMethod
很昂贵,所以我想并行运行它。请注意,myMethod
可能会将许多行添加到arrayDict
。每个进程都会改变自己的ArrayDict
。我不需要同时访问ArrayDict
s
在myMethod
中,我更改arrayDict
中的条目(即,我更改内部numpy
数组),我将条目添加到arrayDict
(即,我向字典添加另一个索引,并在内部数组中写入新值)。最后,我希望能够在arrayDict
的内部numpy
数组变得太小时交换它。这种情况并不经常发生,如果没有更好的解决方案,我可以在程序的非并行部分执行此操作。即使没有阵列交换,我自己的尝试也没有成功
我花了几天时间研究共享内存和python模块。因为我最终将在linux上工作,所以任务似乎相当简单:系统调用fork()
允许有效地处理参数的副本。我当时的想法是在自己的过程中更改每个ArrayDict
,返回对象的更改版本,并覆盖原始对象。为了节省内存和保存复制工作,我使用了额外的数组将数据存储在ArrayDict
中。我知道这本词典仍需复制
from sharedmem import sharedmem
import numpy as np
n = ... # length of the data array
myData = np.empty(n, dtype=object)
myData[:] = [ArrayDict() for _ in range(n)]
done = False
while not done:
consideredData = ... # numpy boolean array of length
# n with True at the index of
# considered data
args = ... # numpy array containing arguments
# for myMethod
with sharedmem.MapReduce() as pool:
results = pool.map(myMethod,
list(zip(myData[considered],
args[considered])),
star=True)
myData[considered] = results
done = ... # depends on what happens in
# myMethod
我得到的是一个分段错误。我通过创建ArrayDict
s到myMethod
的深度副本,并将它们保存到myData
中,从而绕过了这个错误。我真的不明白为什么这是必要的,而且频繁复制我的(可能非常大的)数组(while循环需要很长时间)对我来说似乎不是有效的。然而,至少在一定程度上它起了作用。然而,由于共享内存,我的程序在第三次迭代时出现了一些错误行为。因此,我认为我的方式不是最优的
我读到,可以使用多处理.Array
在共享内存中保存aribtrary numpy数组。但是,我仍然需要共享整个ArrayDict
,其中特别包括一个字典,而字典又是不可挑选的
我怎样才能有效地实现我的目标?是否有可能(且有效)以某种方式使我的对象可拾取
所有解决方案都必须在64位Linux上运行python 3和完整的numpy/scipy支持
编辑
我发现使用多处理“管理器”类和用户定义的代理类共享任意对象是可能的。这会有效率吗?我想利用这一点,我不需要并发访问对象,即使它们没有在主进程中处理。是否可以为我要处理的每个对象创建一个管理器?(我可能对管理者的工作方式仍有一些误解。)这似乎是一个相当复杂的类,我无法完全预测此解决方案是否适用于您的情况。对于这样一个复杂的类,一个简单的折衷方法是使用 如果这不能回答您的问题,那么最好用一个最小的、有效的示例
from concurrent.futures import ProcessPoolExecutor
import numpy as np
class ArrayDict ():
keys = None
vals = None
def __init__ (self):
self.keys = dict ()
self.vals = np.random.rand (1000)
def __str__ (self):
return "keys: " + str(self.keys) + ", vals: " + str(self.vals.mean())
def myMethod (ad, args):
print ("starting:", ad)
if __name__ == '__main__':
l = [ArrayDict() for _ in range (5)]
args = [2, 3, 4, 1, 3]
with ProcessPoolExecutor (max_workers = 2) as ex:
d = ex.map (myMethod, l, args)
当对象被发送到子进程时,您需要返回结果(因为对对象的更改不会传播回主进程)并处理如何存储它们
请注意,对类变量的更改将传播到
相同的流程,例如,如果您的任务多于流程,则更改类
变量将在同一进程中运行的实例之间共享。这通常是不受欢迎的行为
这是并行化的高级接口ProcessPoolExecutor
使用多处理
模块,只能与一起使用。我怀疑ProcessPoolExecutor
的性能类似于。在引擎盖下,ProcessPoolExecutor
,应表现出与Pool
类似的性能(与map一起使用时除外)ProcessPoolExecutor
似乎是python中并发任务的预期未来API
如果可以,使用通常会更快(可以将其替换为ProcessPoolExecutor
)。在这种情况下,对象在进程之间共享,对对象的更新将传播回主线程
如前所述,最快的选择可能是重新构造ArrayDict
,以便它只使用可以由或Array
表示的对象
如果ProcessPoolExecutor
不起作用,并且您无法优化ArrayDict
,则您可能无法使用。关于如何做到这一点,有很多很好的例子
最大的性能增益通常出现在myMethod
中。
而且,正如我提到的,使用线程的开销要比进程的开销大
如何在myMethod中修改或使用arrayDict?(我想你的意思是
myMethod
不是myFunc
?)@gauteh:谢谢你让我注意到打字错误。我纠正了它。我还添加了我如何在myMethod中修改arrayDict的描述