多处理池映射非常慢 运行 一个 Monte Carlo 集合 python 模拟
multiprocessing pool map incredibly slow running a Monte Carlo ensemble of python simulations
我有一个 python 代码,它 运行 是一组参数的二维扩散模拟。我需要多次 运行 代码,O(1000),就像 Monte Carlo 方法一样,每次都使用不同的参数设置。为了更快地做到这一点,我想使用我的机器(或集群)上的所有内核,以便每个内核 运行 是代码的一个实例。
过去,我通过编写一个 python 包装器成功地为 serial fortran 代码完成了此操作,然后使用 multiprocessing map(或 starmap 在多个参数的情况下) 在一组模拟中调用 fortan 代码。它工作得非常好,因为您循环了 1000 次模拟,并且 python 包装器在完成先前的集成后一旦空闲就将新的集成分配给核心。
但是,现在当我将其设置为对 python(而不是 fortran)代码的 运行 多个实例执行相同操作时,我发现它非常慢,比简单地慢得多运行在单核上串行执行代码 1000 次。使用系统监视器,我看到一个核心一次工作,并且它永远不会超过 10-20% 的负载,当然我希望看到 N 个核心 运行ning 接近 100%(当我将 Fortran 作业外包出去)。
我以为可能是写的问题,所以我仔细检查了代码,确保所有绘图都关闭了,实际上有没有 file/disk 访问,我现在只有一个打印语句在最后打印出最终诊断。
我的代码结构是这样的
我在 toy_diffusion_2d.py 中有主要的 python 代码,它有一个带有 运行 参数的字典参数:
def main(arg)
loop over timesteps:
calculation simulation over a large-grid
print the result statistic
然后我写了一个“包装器”脚本,我在其中导入了主要的模拟代码并尝试运行它并行:
from multiprocessing import Pool,cpu_count
import toy_diffusion_2d
# dummy list of arguments
par1=[1,2,3]
par2=[4,5,6]
# make a list of dictionaries to loop over, 3x3=9 simulations in all.
arglist=[{"par1":p1,"par2":p2} for p1 in par1 for p2 in par2]
ncore=min(len(arglist),int(cpu_count()))
with Pool(processes=ncore) as p:
p.map(toy_diffusion_2d.main,arglist)
上面是一个较短的转述例子,我的实际代码较长,所以我把它们放在这里:
主要代码:http://clima-dods.ictp.it/Users/tompkins/files/toy_diffusion_2d.py
您可以 运行 使用默认值,如下所示:
python3 toy_diffusion_2d.py
包装脚本:http://clima-dods.ictp.it/Users/tompkins/files/toy_diffusion_loop.py
您可以 运行 像这样的 4 人合奏:
python3 toy_diffusion_loop.py --diffK=[33000,37500] --tau_sub=[20,30]
(请注意,每个 运行 的最终统计数据略有不同,即使模型具有相同的值也是随机的,随机艾伦卡恩方程的一个版本,以防有人感兴趣,但使用一个关于扩散项的愚蠢的显式求解器)。
正如我所说,第二个并行代码有效,但正如我所说,它非常慢......就像它一直在门控一样。
我也尝试过使用 starmap,但这并没有什么不同,这几乎就像桌面一次只允许一个 python 解释器到 运行...?我花了几个小时在上面,我几乎就要用 Fortran 重写代码了。我确定我只是在做一些非常愚蠢的事情来防止并行执行。
编辑(1):这个问题发生在
4.15.0-112-通用 x86_64 GNU/Linux,带 Python 3.6.9
回复评论,其实我也觉得运行在我的MAC笔记本电脑上没问题...
编辑(2):看来我的问题与其他几个帖子有些重复,抱歉!除了 Pavel 提供的有用链接外,我还发现此页面非常有用:Importing scipy breaks multiprocessing support in Python 我将在下面的解决方案中编辑已接受的答案。
您提供的代码示例在我的 MacOS Catalina 10.15.6 上运行良好。我猜你正在使用一些 Linux 分配器,其中,根据 this answer,由于与 OpenBLAS 库链接,numpy import 可能会干扰核心亲和力。
如果您的 Unix 支持调度程序接口,like this 将起作用:
>>> import os
>>> os.sched_setaffinity(0, set(range(cpu_count)))
另一个问题很好地解释了这个问题is found here,建议的解决方案是:
os.system('taskset -cp 0-%d %s' % (ncore, os.getpid()))
在多处理调用之前插入。
我有一个 python 代码,它 运行 是一组参数的二维扩散模拟。我需要多次 运行 代码,O(1000),就像 Monte Carlo 方法一样,每次都使用不同的参数设置。为了更快地做到这一点,我想使用我的机器(或集群)上的所有内核,以便每个内核 运行 是代码的一个实例。
过去,我通过编写一个 python 包装器成功地为 serial fortran 代码完成了此操作,然后使用 multiprocessing map(或 starmap 在多个参数的情况下) 在一组模拟中调用 fortan 代码。它工作得非常好,因为您循环了 1000 次模拟,并且 python 包装器在完成先前的集成后一旦空闲就将新的集成分配给核心。
但是,现在当我将其设置为对 python(而不是 fortran)代码的 运行 多个实例执行相同操作时,我发现它非常慢,比简单地慢得多运行在单核上串行执行代码 1000 次。使用系统监视器,我看到一个核心一次工作,并且它永远不会超过 10-20% 的负载,当然我希望看到 N 个核心 运行ning 接近 100%(当我将 Fortran 作业外包出去)。
我以为可能是写的问题,所以我仔细检查了代码,确保所有绘图都关闭了,实际上有没有 file/disk 访问,我现在只有一个打印语句在最后打印出最终诊断。
我的代码结构是这样的
我在 toy_diffusion_2d.py 中有主要的 python 代码,它有一个带有 运行 参数的字典参数:
def main(arg)
loop over timesteps:
calculation simulation over a large-grid
print the result statistic
然后我写了一个“包装器”脚本,我在其中导入了主要的模拟代码并尝试运行它并行:
from multiprocessing import Pool,cpu_count
import toy_diffusion_2d
# dummy list of arguments
par1=[1,2,3]
par2=[4,5,6]
# make a list of dictionaries to loop over, 3x3=9 simulations in all.
arglist=[{"par1":p1,"par2":p2} for p1 in par1 for p2 in par2]
ncore=min(len(arglist),int(cpu_count()))
with Pool(processes=ncore) as p:
p.map(toy_diffusion_2d.main,arglist)
上面是一个较短的转述例子,我的实际代码较长,所以我把它们放在这里:
主要代码:http://clima-dods.ictp.it/Users/tompkins/files/toy_diffusion_2d.py
您可以 运行 使用默认值,如下所示:
python3 toy_diffusion_2d.py
包装脚本:http://clima-dods.ictp.it/Users/tompkins/files/toy_diffusion_loop.py
您可以 运行 像这样的 4 人合奏:
python3 toy_diffusion_loop.py --diffK=[33000,37500] --tau_sub=[20,30]
(请注意,每个 运行 的最终统计数据略有不同,即使模型具有相同的值也是随机的,随机艾伦卡恩方程的一个版本,以防有人感兴趣,但使用一个关于扩散项的愚蠢的显式求解器)。
正如我所说,第二个并行代码有效,但正如我所说,它非常慢......就像它一直在门控一样。
我也尝试过使用 starmap,但这并没有什么不同,这几乎就像桌面一次只允许一个 python 解释器到 运行...?我花了几个小时在上面,我几乎就要用 Fortran 重写代码了。我确定我只是在做一些非常愚蠢的事情来防止并行执行。
编辑(1):这个问题发生在 4.15.0-112-通用 x86_64 GNU/Linux,带 Python 3.6.9
回复评论,其实我也觉得运行在我的MAC笔记本电脑上没问题...
编辑(2):看来我的问题与其他几个帖子有些重复,抱歉!除了 Pavel 提供的有用链接外,我还发现此页面非常有用:Importing scipy breaks multiprocessing support in Python 我将在下面的解决方案中编辑已接受的答案。
您提供的代码示例在我的 MacOS Catalina 10.15.6 上运行良好。我猜你正在使用一些 Linux 分配器,其中,根据 this answer,由于与 OpenBLAS 库链接,numpy import 可能会干扰核心亲和力。
如果您的 Unix 支持调度程序接口,like this 将起作用:
>>> import os
>>> os.sched_setaffinity(0, set(range(cpu_count)))
另一个问题很好地解释了这个问题is found here,建议的解决方案是:
os.system('taskset -cp 0-%d %s' % (ncore, os.getpid()))
在多处理调用之前插入。