mpi中的Python多处理

Ray*_*let 13 python mpi multiprocessing

我有一个使用多处理模块编写的python脚本,以便更快地执行.计算是令人尴尬的并行,因此效率随着处理器的数量而变化.现在,我想在MPI程序中使用它,该程序管理跨多台计算机的MCMC计算.此代码调用system()来调用python脚本.但是,我发现当它以这种方式调用时,使用python多处理的效率提升就会消失.

当从MPI调用时,如何让我的python脚本保持多处理的速度增益?

这是一个简单的例子,它类似于我想要使用的更复杂的代码,但显示相同的一般行为.我写了一个名为junk.py的可执行python脚本.

#!/usr/bin/python
import multiprocessing
import numpy as np

nproc = 3
nlen = 100000


def f(x):
    print x
    v = np.arange(nlen)
    result = 0.
    for i, y in enumerate(v):
        result += (x+v[i:]).sum()
    return result


def foo():
    pool = multiprocessing.Pool(processes=nproc)
    xlist = range(2,2+nproc)
    print xlist
    result = pool.map(f, xlist)
    print result

if __name__ == '__main__':
    foo()
Run Code Online (Sandbox Code Playgroud)

当我自己从shell运行它时,使用"top"我可以看到三个python进程,每个进程在我的16核机器上占用100%的cpu.

node094:mpi[ 206 ] /usr/bin/time junk.py
[2, 3, 4]
2
3
4
[333343333400000.0, 333348333450000.0, 333353333500000.0]
62.68user 0.04system 0:21.11elapsed 297%CPU (0avgtext+0avgdata 16516maxresident)k
0inputs+0outputs (0major+11092minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

但是,如果我用mpirun调用它,每个python进程占用cpu的33%,总体而言,它需要大约三倍的运行时间.使用-np 2或更多调用会导致更多进程,但不会加速计算.

node094:mpi[ 208 ] /usr/bin/time mpirun -np 1 junk.py
[2, 3, 4]
2
3
4
[333343333400000.0, 333348333450000.0, 333353333500000.0]
61.63user 0.07system 1:01.91elapsed 99%CPU (0avgtext+0avgdata 16520maxresident)k
0inputs+8outputs (0major+13715minor)pagefaults 0swaps
Run Code Online (Sandbox Code Playgroud)

(补充说明:这是mpirun 1.8.1,Linux Debian版本的python 2.7.3喘息.我听说系统()并不总是允许在MPI程序中,但它在这台计算机上已经为我工作了五年.例如,我在MPI程序中调用了来自system()的基于pthread的并行代码,并且根据需要使用100%的cpu作为每个线程.另外,如果你打算建议在串行中运行python脚本,只是在更多节点上调用它... MCMC计算涉及需要以同步方式移动的固定数量的链,因此遗憾的是,计算不能以这种方式重组.)

Jon*_*rsi 11

OpenMPI的mpirun,v1.7及更高版本,默认将进程绑定到核心 - 也就是说,当它启动python junk.py进程时,它会将它绑定到它将运行的核心.这很好,并且是大多数MPI用例的正确默认行为.但是这里每个MPI任务都会分支更多进程(通过多处理包),并且那些分叉进程继承其父进程的绑定状态 - 所以它们都绑定到同一个核心,在它们之间进行斗争.(顶部的"P"列将显示它们都在同一个处理器上)

如果你mpirun -np 2,你会发现两组三个进程,每个进程在不同的核心上,每个进程在它们之间竞争.

使用OpenMPI,您可以通过关闭绑定来避免这种情况,

mpirun -np 1 --bind-to none junk.py
Run Code Online (Sandbox Code Playgroud)

或者选择其他一些在运行的最终几何形状下有意义的绑定.MPICH 与hydra类似的选择.

请注意,带有mpi的子进程的fork()并不总是安全或受支持,特别是对于使用infiniband互连运行的集群,但OpenMPI的mpirun/mpiexec会在不安全的情况下发出警告.

  • 抱歉,哪个部分的答案?使用 --bind-to none 启动将避免 CPU 问题。至于 fork 的问题,OpenMPI 的 mpirun/mpiexec 会让你知道你是否在 fork-ing 不安全的情况下运行,你可以在/如果它出现时解决这个问题。 (2认同)