填补了并行字典多处理

问题描述:

昨天我问了一个问题:Reading data in parallel with multiprocess填补了并行字典多处理

我得到了很好的答案,我实现了在我标记为正确答案中提到的解决方案。

def read_energies(motif): 
    os.chdir("blabla/working_directory") 
    complx_ener = pd.DataFrame() 
    # complex function to fill that dataframe 
    lig_ener = pd.DataFrame() 
    # complex function to fill that dataframe 
    return motif, complx_ener, lig_ener 

COMPLEX_ENERGIS = {} 
LIGAND_ENERGIES = {} 
p = multiprocessing.Pool(processes=CPU) 
for x in p.imap_unordered(read_energies, peptide_kd.keys()): 
    COMPLEX_ENERGIS[x[0]] = x[1] 
    LIGAND_ENERGIES[x[0]] = x[2] 

然而,这种解决方案需要的时间是相同的,如果我只想遍历peptide_kd.keys()和填补DataFrames一个接一个。为什么?有没有一种方法可以同时填充所需的字典,并且实际上可以提高速度?我正在48核心HPC上运行它。

+0

这可能是使用多处理的开销大于进行复杂函数处理的开销。也许'read_energies()'每次处理一个可变数字的数据框会让你调整一些事情,直到它变得有利。 – martineau

在(1)启动每个进程时,(2)必须将pandas.DataFrame(等)复制到多个进程中,会产生大量开销。如果你只需要并行填写dict,我建议使用共享内存dict。如果没有密钥被覆盖,那么很容易,你不必担心锁。 (请注意,我在下面使用multiprocess,这是multiprocessing的分支 - 但只有我可以从解释器演示,否则,您必须从__main__开始执行以下操作)。

>>> from multiprocess import Process, Manager 
>>> 
>>> def f(d, x): 
... d[x] = x**2 
... 
>>> manager = Manager() 
>>> d = manager.dict() 
>>> job = [Process(target=f, args=(d, i)) for i in range(5)] 
>>> _ = [p.start() for p in job] 
>>> _ = [p.join() for p in job] 
>>> print d 
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16} 

这种解决方案并不能使dict的副本跨进程共享,所以开销的部分降低。对于像pandas.DataFrame这样的大对象,与简单操作(如x**2)的成本相比,它可能很重要。类似地,产生一个Process可能需要时间,并且您可能能够通过使用线程(即从multiprocess.dummy而不是multiprocess为您最初发布的解决方案或上面的解决方案)更快地(对于轻量级对象)执行上述操作。

如果需要共享DataFrames(如代码提示,而不是因为这个问题问),你也许可以通过创建一个共享内存numpy.ndarray做到这一点。

+0

感谢您的回答!我现在要试试这个,但首先我想问一些问题。我不明白所提到的“共享”数据框(我猜想的变量)之间的差异。为什么我的代码暗示我使用共享的DataFrame?我想要并行处理的工作就像你描述的那样,填写一个字典,然后以不同的方式使用它(读取它里面的数据),但不要改变它里面的任何东西。 –

+0

我说你可能会看到共享内存数组的原因是,你从每个'Process'返回两个'DataFrame'实例。但是,很难指出您是否需要这样做,因为您仅提供元代码。 –

+0

哦,我明白了。我需要两个'DataFrames'。返回其中两个是否有问题?分两步做这件事会容易吗? –