使用多处理时有一个全局变量是否有效?

时间:2018-04-15 13:09:11

标签: python pandas multiprocessing python-multiprocessing

请考虑这个很酷的设置:

from multiprocessing import Pool, cpu_count
import pandas as pd
import numpy as np

def helper(master_df):
    max_index = master_df['key'].max()
    min_index = master_df['key'].min()
    #note how slave is defined before running the multiprocessing
    return slave.iloc[min_index:max_index,]

from datetime import datetime

master = pd.DataFrame({'key': [1,2,3,4,5,6,7,8,9,10]})
slave = pd.DataFrame({'key': [1,2,3,4,5,6,7,8,9,10],
                      'value' : ['a','b','c','d','e','f','g','h','i','j']})

if __name__ == '__main__':
     startTime = datetime.now()
     p = Pool(cpu_count() - 1)
     ret_list = p.map(helper, [master.iloc[1:5,], master.iloc[5:10,]])
     print datetime.now() - startTime
     print ret_list

基本上,我在内存中有两个数据帧。

正如您在主要的多处理代码中所看到的,p.map作为参数接收master数据帧的两个块。

然后,(我想)multiprocessing生成的每个进程都将访问slave数据帧并使用它(不进行修改)。实际上,您可以在helper函数中看到每个进程都会slice slave数据框,并使用它进行一些计算。

我的问题是:在每个进程访问的全局命名空间中定义数据帧是否有效?我不确定在RAM利用率方面会发生什么(每个进程在内存中重复slave?)。这不是一个好主意,因为实际上masterslave都非常大。

我想一种替代方法是将tuple发送到p.map,其中包含分块master和相应的切片slave数据帧。不确定这是一个好主意(以及如何正确地做到这一点)?

有什么想法吗? 谢谢!

1 个答案:

答案 0 :(得分:3)

这令人惊讶地取决于操作系统multiprocessing is implemented differently in Windows and Linux

  • 在Linux中,通过fork变体创建进程,其中子进程最初与父进程共享相同的地址,然后执行COW(写入时复制)。在Linux下,我经常让子进程访问只读的全局DataFrame,一切都很好(包括性能)。

  • 在Windows中,很明显,整个过程都会被启动,并且您可能会将DataFrame复制到它上面的性能损失(除非由它完成的处理足够大以使成本可以忽略不计) ,但我还没有在Windows上使用过Python,所以没有经验。

修改

joblib与DataFrames一起使用的示例:

import joblib
import pandas as pd

df = pd.DataFrame(dict(a=[1, 3], b=[2, 3]))

def foo(i, df):
    return df + i

from joblib import Parallel, delayed
Parallel(n_jobs=2)(delayed(foo)(i, df) for i in range(10))

您还可以将df用作全局:

def foo(i):
    return df + i

from joblib import Parallel, delayed
Parallel(n_jobs=2)(delayed(foo)(i) for i in range(10))