1

我需要对一些大数据帧的不同切片进行一些计算。

假设我有 3 个大数据框df1df2并且df3.
每个都有一"Date"列。
我需要根据日期切片对这些数据帧进行一些计算,并且由于每次迭代都独立于其他迭代,因此我需要同时进行这些迭代。

df1              # a big dataframe
df2              # a big dataframe
df3              # a big dataframe

在此处输入图像描述

所以我定义了我想要的函数,在每个子进程中,首先在进程中创建一个 , ,的切片df1,然后进行其他计算。df2df3

由于df1和是全局数据框,df2因此df3我需要将它们指定为函数中的参数。否则将无法识别。

如下所示:

slices = [ '2020-04-11', '2020-04-12', '2020-04-13', ]
# a list of dates to get sliced further

def my_func(slice,df1=df1,df2=df2,df3=df3):
    sliced_df1 = df1[df1.Date >  slice]
    sliced_df2 = df2[df2.Date <  slice]
    sliced_df3 = df3[df3.Date >= slice]
    #
    # other computations
    # ...
    #
    return desired_df

并发处理配置如下:

import psutil
pool = multiprocess.Pool(psutil.cpu_count(logical=False))

final_df = pool.map(my_func,[slice for slice in slices])
pool.close()
final_df = pd.concat(final_df, ignore_index = True)

然而,似乎只有一个核心在执行时上升。

我想由于每个子进程都想访问全局数据帧df1df2并且df3,应该有一个子进程的共享内存,当我通过网络搜索时,我想我必须使用multiprocessing.manager(),但我不确定如何使用它或如果我使用它是对的?

我实际上是并发处理概念的新手,如果有人可以提供帮助,我将不胜感激。

PS:看来我的问题与这篇文章类似。但是,它没有一个公认的答案。

4

1 回答 1

1

“……我(我)使用它是对的吗?


一个)multiprocess != multiprocessing

好吧,您可能已经注意到,multiprocessing-module 与 Mike McKerns 的multiprocess-module 不同。(后者的承诺和属性这些天仍然隐藏,因为模块维护者已经在RTFM站点上发布了模块文档(是的,ReadTheDocs 最初使用Read-The-F *****g-Manual站点标识,所以不是我的想法),目前无法访问 -as-of-2020-04-,因为地址转换为https://multiprocess.readthedocs.io/en/latest/无法呈现任何multiprocess完全与模块相关的内容(如果@Mike McKerns 能够介入并修复这一缺陷,那就太好了,否则 Pathos、Dill 和他发表的其他作品以非常棒的软件而闻名,不是吗? )。


B)您支付的费用比以往任何时候都多

如果试图避免重复DataFrame的实例,受 RAM 上限的影响,则不能使用基于进程的多处理。这陷入了一个陷阱,即只有一个纯粹[SERIAL]的中央 GIL 锁独裁统治协调一步一步的执行模式(没有提高性能,但恰恰相反......支付附加成本对于线程多路复用,都在等待自己持有 GIL 锁和空闲 RAM-I/O 以获取一些数据以获取/咀嚼/存储(进程))。

如果尝试进入 linux-fork 生成的进程(承担这样做的风险 - 种子文档/关于细节的问题)并使用Manager()-instance (嘿,是的,GIL 锁将再次阻塞,但只有一个 CPU 核心 - 我们听说过关于这一点,我们不是吗?)或其他类似的纯语法技巧来访问或编排对global-s 或从主对象的“共享”对象的访问,再次,这样做的成本将违背您的意愿为了获得性能,(网络 I/O 延迟屏蔽用例除外)永远不会有可衡量的优势,通常情况恰恰相反——您在附加管理成本方面付出的代价将比以往任何时候都多就希望提高的性能而言。

如果DataFrame通过参数传递传递所有-instances(正如您的语法尝试做的那样),您的进程(无论是分叉还是衍生)将支付更多的附加开销成本(并且所有进程都将具有原始的完整副本( df1, df2, df3, )... 是的,RAM 将证明这一点)加上与多处理相关的附加开销成本将包括巨大且毁灭性的 SER/DES 成本,因为这些 BIG-FAT 肉块必须通过 SER/DES(通常通过pickle.dumps()p2p 数据传输(数据流)上的 SER 阶段 + XFER 阶段 + DES 阶段在pickle.loads()......所有这些执行3 * len ( [ slice for slice in slices ] )时间,具有 RAM 争用上限,由中央控制 CPU 争用节流-side 上的 GIL-lock __main__,因为需要先执行所有三个( SER, XFER, )-phases 在其一侧,如果 RAM 允许,在“远程”-DES-phases 开始之前,很可能在已经开始的大量交换颠簸下。

因此,对于任何高性能计算来说,这两种模式都更像是一种反模式,不是吗?

如果不是所有这些与 python/GIL 相关的问题,那么性能科学就会对你不利——有关详细信息和定量方法,请参阅修订后的阿姆达尔定律中的加速陷阱。


有疑问?

基准,基准,基准。

事实很重要。

于 2020-04-22T11:03:24.597 回答