我已经阅读了dask文档,博客和SO,但是我仍然不清楚如何做到这一点。我的用例:
总结:
可能的陷阱/问题:
最有效的解决方案似乎是,如果我们只能将ref-data加载到内存中一次,则使其对处理事件的其他多个进程具有只读权限
通过在每台计算机上加载引用数据来扩展到多台计算机。将文件名推送到计算机以执行。
有什么想法要实现吗?
非常感谢您的帮助
答案 0 :(得分:1)
我也遇到过类似的问题,即运行尴尬的并行作业,这些作业都在同一查找“引用”表(或并行进程的每个实例所需的任何大内存只读变量)中获取数据。当您处于遵循“写时复制”语义的环境(例如linux)中时,将查找表放置在全局范围内始终可以非常有效地工作,这在下面很好地解释了: Shared-memory objects in multiprocessing
这是一个简单的并行工作流程:
from multiprocessing import Pool
# Load your reference data, do that only once
# here in the parent process
my_ref_lookup = load_ref_data(your_data_file)
def your_parallel_function(my_file_path):
my_new_data = load_data(my_file_path)
# process my_new_data with some lookup in my_ref_lookup
# which is known from the parent process.
processed_data = do_stuff(my_new_data)
# you could here write something on disk
# and/or return the processed_data
return processed_data
with Pool(processes = 5) as Pool:
list_of_result = Pool.map(your_parallel_function, your_list_of_file_paths)
此处your_parallel_function
的执行将在例如5个工作程序,一次在your_list_of_file_paths
中提取5个文件,所有子进程都可以访问my_ref_lookup
,而无需复制它们。
经过一段时间的Dask和手袋收藏,我再也没有发现类似或简单的行为。在我尝试使用Dask的过程中,只读变量在全局范围内以这种方式共享,最终被需要它的许多工作人员复制,这激增了内存并使内核崩溃。我从未在任何Dask文档中见过此案。 Dask文档中唯一与此远程相关的参考是关于避免全局状态:https://docs.dask.org/en/latest/delayed-best-practices.html#avoid-global-state 但这显示了共享变量被修改为延迟函数的情况,这与当前仅共享“只读”数据的问题不同。
答案 1 :(得分:0)
我找到了关于{python} Ray框架的blog post。尽管Ray的业务目的非常不同,但它们面临着相同的核心要求:许多并行流程利用了只读的共享内存数据帧。他们正在描述和解释为什么他们选择使用Apache Arrow和pyarrow。听起来很有趣,我们将尝试用例。
答案 2 :(得分:-1)
您可以考虑的一些事情
每个dask worker进程可以具有任意数量的线程。线程之间共享数据不需要复制,但是进程之间共享则需要复制。因此,您应该尝试使用进程/线程组合来找到最适合您的
通常最好将数据加载到工作线程中,而不要从客户端传递数据,即使在进程之间进行复制非常有效。如果您有足够的内存为每个工作人员保留参考数据,那显然是最好的,尽管Dask会尽力解决任务的常见中间依赖项。
每个任务都会带来一些开销,并且可能导致中间件从一台计算机移动到另一台计算机。尽管在优化时可能会融合一些线性的过程链,但您最好编写一个函数,该函数从一个函数开始依次调用各个阶段,然后将该函数作为单个任务针对数据的每个部分调用一次。
示例
f = client.submit(read_function, ref_filename)
out = client.map(process_function, list_of_inputs, ref=f)
在此示例中,process_function
接受一个输入(可能是一个元组),而ref=
则接受一个可选输入,即已加载的引用数据。 Dask将根据需要将参考数据复制给工作人员。