【发布时间】:2022-11-16 02:34:15
【问题描述】:
Python concurrent.futures.ProcessPoolExecutor 因 RAM 满而崩溃
程序说明
嗨,我有一个计算量大的函数,我想并行运行。该函数是一个接受输入的测试:
- 要测试的 DataFrame
- 运行计算所基于的参数。
返回值是一个简短的计算结果列表。
我想在具有不同参数和相同输入 DataFrame 的 for 循环中运行相同的函数,基本上运行蛮力来为我的问题找到最佳参数。
我写的代码
我目前正在从模块 concurrent.futures 中与 ProcessPoolExecutor 同时运行代码。
import concurrent.futures
from itertools import repeat
import pandas as pd
from my_tests import func
parameters = [
(arg1, arg2, arg3),
(arg1, arg2, arg3),
...
]
large_df = pd.read_csv(csv_path)
with concurrent.futures.ProcessPoolExecutor() as executor:
for future in executor.map(func, repeat(large_df.copy()), parameters):
test_result = future.result()
...
问题
我面临的问题是我需要运行大量迭代,但我的程序几乎立即崩溃。
为了不让它崩溃,我需要将它限制为最多 4 个 worker,这是我 CPU 资源的 1/4。
with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:
...
我发现我的程序因满 RAM (16 GB) 而崩溃。我发现奇怪的是,当我在更多的 worker 上运行它时,它逐渐消耗越来越多的 RAM,它从未释放,直到它崩溃。
我没有传递 DataFrame 的副本,而是尝试传递文件路径,但除了减慢我的程序之外,它没有改变任何东西。
您是否知道为什么会出现该问题以及如何解决?
【问题讨论】:
-
所以你已经确定
my_tests.func有内存泄漏......我们需要了解更多关于func的信息才能提供帮助。除了泄漏,如果返回数据 (future.result()) 的大小很大,您需要确保您正在处理它并在主进程中释放它。 -
如果泄漏在第 3 方库中,则必须在
func内部使用,设置执行程序的max_tasks_per_child参数,以便定期重启工作进程。这会增加开销,但会强制库重新加载/清除内存 -
如果问题是返回数据(
executor.map将在开始循环之前等待所有结果完成),您应该改为submit所有任务,然后在您从中收集的所有future对象上调用concurrent.futures.as_completedsubmit。这将允许主进程在结果完成时处理结果,而不是等待它们全部完成(这需要有足够的内存来一次存储所有结果) -
func函数正在使用 numpy 和 pandas 运行多个计算,以根据初始数据帧计算一些值。至于submit和as_completed方法,这是我最初的代码,但问题是一样的。我会研究您的建议并及时通知您。 -
map方法返回一个迭代器,该迭代器在迭代时直接返回下一个结果(即来自func的返回值)而不是Future,然后您必须在Future上调用result方法。
标签: python multiprocessing concurrent.futures process-pool