【问题标题】:Python: How to run simple MPI code on multiple nodes?Python:如何在多个节点上运行简单的 MPI 代码?
【发布时间】:2021-07-10 17:06:06
【问题描述】:

我想在使用多个节点的 HPC 上运行一个简单的并行化 MPI python 代码。

SLURM 被设置为 HPC 的作业调度程序。 HPC 由 3 个节点组成,每个节点有 36 个内核。 Open MPI 和 MPICH 都可以作为 MPI 实现。

我要运行的代码如下:

import sys
import numpy as np
import socket
import time
from mpi4py.futures import MPIPoolExecutor

# Define simple function
def myFun(x):
    time.sleep(5)
    print('Process is running on host: %s' % (socket.gethostname()))
    return x+2

if __name__ == '__main__':
    timestamp1 = time.perf_counter()
    # Create small set of random input data
    dat = [np.random.rand(3, 2) for x in range(8)]
    
    # Using mpi4py for multiprocessing
    with MPIPoolExecutor(max_workers=8) as pool:
        # Run function with myFun and dat as map operation
        result = pool.map(myFun, dat)
    
    timestamp2 = time.perf_counter()
    delta_t = timestamp2 - timestamp1
    
    print('Runtime of code: ', delta_t)

此代码非常简单,仅用于了解如何使其工作。该代码基于 Hristo 'away' Iliev 在此线程 Python: how to parallelizing a simple loop with MPI 中的建议答案,并进行了一些细微的更改。我真的很喜欢这段代码,因为我实际上需要重写的用例使用了多处理的池类。

我的默认 *.sbatch 文件基本上设置如下:

#!/bin/bash

# SLURM Setup -------------------------------------------------

#SBATCH --job-name=Test_MPI
#SBATCH --output=job.%j.out         
#SBATCH --error=job.%j.err
#SBATCH --nodes=1           
#SBATCH --ntasks-per-node=9     
#SBATCH --mem=1G            

module load ...
eval "$(conda shell.bash hook)"
conda activate ...

srun -n 1 python -m mpi4py.futures stackExample2.py

在这种情况下,我保留 9 个处理器,因为我使用 1 个主进程和 8 个工作进程(使用 MPIPoolExecutor(max_workers=8) 定义)。当只是并行化它时,这工作正常。

当我想将此代码用于>36 个进程时,我需要能够在多个节点上运行它。但到目前为止,我还做不好。首先我只调整#SBATCH --nodes 和 --ntasks-per-node。在这种情况下,我设置节点 = 2 和 ntasks-per-node=5,因为我需要确保至少保留 9 个进程。检查 *.err 文件时,我得到了这个:

srun: Warning: can't run 1 processes on 2 nodes, setting nnodes to 1

它忽略了 --nodes =2 的设置,并继续执行,就像设置了 --nodes=1 和 --ntasks-per-node=9 一样。查看 *.out 文件时,该函数显然只打印了 hostname1。

我从各种来源阅读了很多帖子、示例和介绍。在大多数情况下,它们使用简单的 srun 命令,例如“srun python myprogram.py”。所以我尝试了:

srun python -m mpi4py.futures stackExample2.py

这次我的代码在两台主机上运行,​​但它在主机名 1 上运行了 5 次,在主机名 2 上运行了 5 次。这不是我想要的,因为我想使用主机 1 和主机 2 的处理器运行一次代码。

我尝试了各种其他可能性,包括使用 mpirun/mpiexec 代替 srun、-host 选项等,但仍然无法正确使用。这就提出了代码是否缺少某些东西的问题。

我是否需要更改代码才能在多个节点上使用进程? 还是我仍然使用错误的 srun 调用?

提前谢谢你!

【问题讨论】:

  • 此功能在内部依赖于MPI_Comm_spawn(),因此不太可能与srun 一起使用,您应该改用mpirun
  • @GillesGouaillardet 我尝试使用 mpirun。到目前为止,我能够在多个节点(在本例中为 2 个节点)上并行运行代码多次。但是我试图在使用位于两个节点上的进程时并行运行一次代码。
  • 您需要mpirun -np 1 ... 才能开始一项任务。然后,假设 mpi4py 在后台使用的 MPI 库正确支持和检测 SLURM,MPI_Comm_spawn() 应该在两个节点上生成任务。

标签: python parallel-processing mpi openmpi slurm


【解决方案1】:

我找到了解决问题的方法。

首先,您可以在使用多个主机的处理器时运行此代码一次。

您显然可以告诉我,我对编写用于并行或分布式执行的代码还很陌生。我缺乏经验导致我走错了路,因为我认为一切都设置得很完美。

Open MPI 实现无法正常工作。我最好的猜测是设置或编译时出了点问题。这是相对难以实现的,因为它:

  1. 似乎可以正确检测到 SLURM 用于作业和资源调度的情况
  2. 可以在单个主机上并行执行代码
  3. 能够同时在多个主机上并行运行代码,彼此独立

我看到了一堆使用简单 HelloWorld 代码(主要是 C 和 Python)的示例,展示了运行分布式代码的一般可能性。但我无法重新创建这些示例提供的结果。我确保使用相同的代码和 mpirun/mpiexec 或 srun 调用,而是返回类似:

Hello, I'm rank 0 of 3 running on host1
Hello, I'm rank 1 of 3 running on host2
Hello, I'm rank 2 of 3 running on host1
Hello, I'm rank 3 of 3 running on host2

我的结果是这样的:

Hello, I'm rank 0 of 3 running on host1
Hello, I'm rank 0 of 3 running on host2
Hello, I'm rank 0 of 3 running on host1
Hello, I'm rank 0 of 3 running on host2

这时我意识到我的实现出了点问题。我无法确定确切的问题是什么。我看到一些使用标志 --mca 来设置首选通信线路的帖子,但实际上无法从中做出任何事情。 正如我在最初的问题中提到的,我们有两个 MPI 实现(OpenMPI v3.1.3(默认加载),MPICH 3.3)我们可以作为模块加载。

我切换到 MPICH 并使用 mpiexec-call 运行完全相同的 HelloWorld 代码,现在产生了预期的结果。随后我运行了最初问题的代码,我能够使用来自多个主机的处理器运行它一次。即使我找到了建议,我还是会联系 HPC 管理员并尝试找出我们的 Open MPI 实施有什么问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 2020-09-10
    • 2020-02-11
    • 2020-09-27
    • 2019-11-03
    • 1970-01-01
    • 2021-04-20
    相关资源
    最近更新 更多