Python 以令人尴尬的并行方式运行MPI代码(在PBS Torque群集上)

Python 以令人尴尬的并行方式运行MPI代码(在PBS Torque群集上),python,parallel-processing,mpi,pbs,torque,Python,Parallel Processing,Mpi,Pbs,Torque,我编写了一个基于MPI的C代码,用于并行执行数值模拟。由于我的一些糟糕的设计,我在代码中内置了一些固有的MPI依赖项(数组结构,MPI-IO)。这意味着如果我想以串行方式运行代码,我必须调用 mpiexec -n 1 c_exe 主要问题 我在Python工作流中使用我的C代码,该工作流在下面的循环中进行了简化 import os import subprocess homedir = os.getenv('PBS_O_WORKDIR') nevents = 100 for ievent

我编写了一个基于MPI的C代码,用于并行执行数值模拟。由于我的一些糟糕的设计,我在代码中内置了一些固有的MPI依赖项(数组结构,MPI-IO)。这意味着如果我想以串行方式运行代码,我必须调用

mpiexec -n 1 c_exe
主要问题 我在Python工作流中使用我的C代码,该工作流在下面的循环中进行了简化

import os 
import subprocess

homedir = os.getenv('PBS_O_WORKDIR')

nevents = 100
for ievent in range(nevents):

    perform_workflow_management()
    os.chdir(ievent)
    subprocess.call('mpiexec -n 1 c_exe', Shell=True)
    os.chdir(homedir)
Python工作流主要用于管理,并调用执行数字密集型工作的C代码

PythonFor循环中的任务是独立的,因此我想采用一种令人尴尬的并行方案来在事件上并行化循环。基准测试表明,在事件上并行化循环将比使用并行MPI调用的串行循环更快。此外,我正在PBS扭矩群集上运行此功能

我不知道如何有效地做到这一点。这种复杂性似乎是由于对我的C代码的MPI调用和多个MPI任务的分配引起的

我以某种形式尝试过的东西

pbsdsh的包装器-导致处理器分配问题

MPMD与mpiexec-理论上做我想做的,但失败了,因为所有进程似乎共享MPI_COMM_世界。我的C代码为基于域的并行性建立了笛卡尔拓扑;这里发生冲突

有没有人对我如何以一种尴尬的并行方式实现这一点提出建议?理想情况下,我想提交一份工作申请

qsub -l nodes=N:ppn=1,walltime=XX:XX:XX go_python_job.bash
其中N是处理器的数量。在每个进程上,我希望能够向我的C代码提交独立的mpiexec调用


我知道问题的一部分在于设计缺陷,但如果我能找到一个解决方案而不必重构大部分代码,那将是有利的

首先,使用任何合适的MPI实现,您不必使用
mpiexec
来启动单例MPI作业-只需运行可执行文件(MPI标准,§10.5.2单例MPI_INIT)。它至少适用于OpenMPI和MPICH系列

其次,任何合适的DRM(分布式资源管理器,又称批处理排队系统)都支持阵列作业。这些是SPMD的DRM等价物-具有相同作业文件的多个作业

要使用Torque获取阵列作业,请在命令行或作业脚本中传递
qsub
从到的
-t选项:

#PBS -t 1-100
...
然后,在Python脚本中获取
PBS_ARRAYID
环境变量的值,并使用它区分不同的实例:

import os 
import subprocess

homedir = os.getenv('PBS_O_WORKDIR')
ievent = os.getenv('PBS_ARRAYID')

perform_workflow_management()
os.chdir(ievent)
subprocess.call('./c_exe', Shell=True)
os.chdir(homedir)
正如@Zulan已经提到的,这允许作业调度器通过回填更好地利用集群的资源(如果您的Torque实例与Maui或类似的高级调度器配对)

阵列作业的优点是,尽管从您的角度来看,它们看起来和工作(大部分)像单个作业,但调度程序仍然将它们视为单独的作业,并单独调度它们


这种方法的一个可能缺点是,如果作业排他地调度,即没有两个作业可以共享一个计算节点,那么利用率将非常低,除非您的群集节点每个只有一个单核CPU(现在很不可能)。

1)我们谈论的每个事件有多少“事件”/“时间”?对于每个事件只启动一个作业(通过python)可能是可行的——将最大程度的并行性暴露给批处理系统。这样你可以得到最好的补货,但是你可能会使批处理系统过载。2) 您是否尝试过将
MPI\u COMM\u WORLD
的所有实例替换为
MPI\u COMM\u SELF
,初始工作流管理除外?因此事件通常为100次,对于典型的问题大小(串行运行),每次C调用大约需要10分钟。我还没有尝试过MPI_COMM_SELF,尽管这似乎是一个解决方案。如果我按如下方式运行MPMD
mpiexec-n1a.out:-n1b.out
,并将
MPI\u COMM\u WORLD
替换为
MPI\u COMM\u SELF
,每个实例是否只访问它启动时所在的列组?集群上每个节点是否都可以执行多个作业,或者,即使您只请求一个核心,您是否总是阻止一个完整的节点?我相信每个节点可能有多个作业。我使用MPI_COMM_SELF测试了一个版本,并使用mpiexec测试了MPMD调度。事情似乎按预期进行。mpiexec分配不同的节点,MPI_COMM_自行“序列化”MPI代码。有趣的是,
Singleton MPI_INIT
是标准的一部分。我不想建议一个完全依赖于实现的省略mpiexec的解决方案。这很有用。过去我在没有mpiexec的情况下运行了./c_exe,但不知道与
单例MPI_INIT
相关的规则。通过这种方式,MPI_COMM_WORLD被设置为单个进程,我的代码运行良好。至于作业数组,我避免了这种情况,因为它涉及向队列提交一系列作业。对于我的工作流,我预先请求我的节点,然后继续从工作流中为节点分配任务(在主节点上运行)。如果我使用单例MPI调用,调用pbsdsh的方案是否合理?