我有一个函数f(x)
,我想并行评估值列表xrange
。该函数执行以下操作:
def f(x, wrange, dict1, dict2):
out_list = []
v1 = dict1[x]
for w in wrange:
v2 = dict2[x-w]
out_list += [np.dot(v1, v2)]
return out_list
它从字典dict1
取值矩阵,从字典dict2
取向量,然后将它们相乘。现在,我通常并行执行此操作的方法如下:
import functools
import multiprocessing
par_func = functools.partial(f, wrange=wrange, dict1=dict1, dict2=dict2)
p = multiprocessing.Pool(4)
ssdat = p.map(par_func, wrange)
p.close()
p.join()
现在,当dict1
和dict2
是大词典时,这将导致代码失败并显示错误
File "/anaconda3/lib/python3.6/multiprocessing/connection.py", line 393, in _send_bytes header = struct.pack("!i", n)
struct.error: 'i' format requires -2147483648 <= number <= 2147483647
,我认为这是因为pool
为我的函数的每次评估都复制了dict1
和dict2
。有没有有效的方法来将这些词典设置为共享内存对象? map
是执行此操作的最佳功能吗?
答案 0 :(得分:2)
如果您使用的是基于fork
的系统(阅读:不是Windows),此问题的一种解决方案是将dict
s放在全局变量中,编写一个不包含以下内容的函数:不能将它们作为参数,而只是从其自身的全局变量访问它们并使用它。 functools.partial
is, unfortunately, unsuited to this use case,但您的用例可轻松替换为全局变量和def
版的功能:
import multiprocessing
# Assumes wrange/dict1/dict2 defined or imported somewhere at global scope,
# prior to creating the Pool
def par_func(x):
return f(x, wrange, dict1, dict2)
# Using with statement implicitly terminates the pool, saving close/join calls
# and guaranteeing an exception while mapping doesn't leave the pool alive indefinitely
with multiprocessing.Pool(4) as p:
ssdat = p.map(par_func, wrange)
在创建dict1
之后,dict2
/ Pool
的更改将不会在进程之间反映,但是无论如何您似乎都以只读方式使用它,因此没问题。
如果您使用的是Windows,或者需要更改dict
,则可以始终make a multiprocessing.Manager
and make dict
proxies with the dict
method of the manager(这些共享的dict
,在分配密钥时进行更新),但是比较难看而且速度较慢,因此,如果可能的话,我不建议这样做。
答案 1 :(得分:0)
如果要使用多处理在进程之间共享内存,则需要与multiprocessing.Array显式共享对象。这不是理想的,因为您想访问字典中的元素,并且找到正确的数据可能很耗时。如果确实成为您的问题,可能有一些解决方法。
如@Peque所述,另一种选择是使用threading。使用线程时,内存会在所有进程之间自动共享,但是由于global interpreter lock(GIL),您可能会遇到性能问题。 GIL是Python保持线程安全并避免出现竞争状况的方法。