我有一个有趣的多处理问题,我可以利用它的结构。这个问题涉及Pandas中的大约80列DataFrame
(df
),其中包含许多列和一个在对上运行的函数func
(〜80 * 79 / df
中的这些列的2对),并且每次运行都需要相当短的时间。
代码看起来像
mgr = Manager()
ns = mgr.Namespace()
ns.df = df
pool = Pool(processes=16)
args = [(ns, list(combo)) for combo in list(combinations(df.columns, 2))]
results = pool.map(func, args)
pool.close()
上述速度并不比没有游泳池快但速度快,但速度提高了7倍左右。我担心这么多电话的开销是问题所在。有没有一种好方法可以在这里利用MultiProcessing的结构?
答案 0 :(得分:0)
这是一个相当标准的结果。并行运行时,没有什么能够完美线性扩展,因为设置每个进程并在进程之间传递数据所需的开销。请记住,(80 * 79) / 2 = 3,160
实际上是一个非常小的数字,假设该函数不是非常计算密集的(即需要很长时间)。在其他条件相同的情况下,函数越快,使用多处理的开销成本就越高,因为设置附加进程的时间相对固定。
多处理的开销主要来自内存,如果您必须对大型数据集进行多次复制(如果函数设计不当,则每个进程一次复制),因为进程不共享内存。假设您的功能已设置为可以轻松并行化,只要您不超过计算机上的处理器数量,添加更多进程就会很好。大多数家用计算机没有16个处理器(典型值最多为8个),结果(并行速度快7倍)与少于16个处理器的处理器一致。您可以使用multiprocessing.cpu_count()
检查计算机上的处理器数量。
修改强>
如果通过传递列字符串来并行化函数,那么它将重复创建数据帧的副本。例如:
def StringPass(string1, string2):
return df[string1] * df[string2]
如果并行化StringPass,它将每个进程至少复制一次数据帧。相反:
def ColumnPass(column1, column2):
return column1 * column2
如果只传递必要的列,ColumnPass将仅在并行运行时复制每次调用函数所需的列。因此,虽然StringPass(string1, string2)
和ColumnPass(df[string1], df[string2])
将返回相同的结果,但在多处理中,前者将生成全局df
的几个低效副本,而后者仅将每个调用的必要列复制到功能。