利用fork系统调用来完全避免读/写或序列化



我使用的是macbook,因此,多处理将使用fork系统调用,而不是生成新进程。此外,我正在使用Python(带有多处理或Dask(。

我有一个很大的熊猫数据帧。我需要有许多并行的子流程来处理这一大数据帧的一部分。假设这个表有100个分区需要并行处理。我想避免需要制作100个这个大数据帧的副本,因为这会占用内存。因此,我目前采用的方法是对其进行分区,将每个分区保存到磁盘上,并让每个进程读取它们,以处理它们各自负责的部分。但是这种读/写对我来说非常昂贵,我想避免它

但是,如果我为这个数据帧制作一个全局变量,那么由于COW行为,每个进程都可以从这个数据帧中读取,而无需制作它的实际物理副本(只要它不修改它(。现在我的问题是,如果我制作一个全局数据帧并将其命名为:

global my_global_df
my_global_df = one_big_df

然后在我做的一个子过程中:

a_portion_of_global_df_readonly = my_global_df.iloc[0:10]
a_portion_of_global_df_copied = a_portion_of_global_df_readonly.reset_index(drop=True)
# reset index will make a copy of the a_portion_of_global_df_readonly
do something with a_portion_of_global_df_copied

如果我这样做,我会创建整个my_global_df的副本还是只创建a_portion_of_global_df_readonly的副本,从而避免复制100个one_big_df

另一个更普遍的问题是,当(假设人们使用UNIX(将数据设置为全局变量将有效地使其在所有子进程中都可用时,为什么人们必须处理Pickle序列化和/或对磁盘的读/写以跨多个进程传输数据?使用COW作为使任何数据可用于一般子流程的手段是否存在危险?

[来自下面线程的可复制代码]

from multiprocessing import Process, Pool
import contextlib
import pandas as pd
def my_function(elem):
return id(elem)
num_proc = 4
num_iter = 10
df = pd.DataFrame(np.asarray([1]))
print(id(df))
with contextlib.closing(Pool(processes=num_proc)) as p:
procs = [p.apply_async(my_function, args=(df, )) for elem in range(num_iter)]
results = [proc.get() for proc in procs]
p.close()
p.join()
print(results)

总结注释,在Mac或Linux等分叉系统上,子进程具有父地址空间的写时拷贝(COW(视图,包括它可能持有的任何DataFrame。在不更改父进程或其他同级子进程中的数据的情况下,在子进程中使用和修改数据帧是安全的。

这意味着没有必要序列化数据帧以将其传递给子帧。您所需要的只是对数据帧的引用。对于Process,您可以直接传递引用

p = multiprocessing.Process(target=worker_fctn, args=(my_dataframe,))
p.start()
p.join()

如果使用QueuePool等其他工具,则数据可能会被序列化。您可以使用工作人员已知但未实际传递给工作人员的全局变量来解决该问题。

剩下的是返回数据。它仅在子级中,仍然需要序列化才能返回给父级。

相关内容

  • 没有找到相关文章