使多处理池适应mpi4py

时间:2014-07-10 07:01:20

标签: python multiprocessing mpi4py

我使用多处理池在Python中运行并行仿真,并且在具有多个核心的计算机中运行良好。现在我想使用多个节点在集群上执行程序。我想多处理不能应用于分布式内存。但mpi4py似乎是个不错的选择。那么这些代码最简单的mpi4py等价是什么:

from multiprocessing import Pool

pool = Pool(processes=16)

pool.map(functionName,parameters_list)

3 个答案:

答案 0 :(得分:3)

我的旧版程序包构建于mpi4py之上,可为MPI个作业启用功能并行映射。它不是为速度而构建的 - 它是为了从解释器启用MPI并行映射到计算集群而构建的(即无需从命令行的mpiexec运行) 。基本上:

>>> from pyina.launchers import MpiPool, MpiScatter
>>> pool = MpiPool()
>>> jobs = MpiScatter()
>>> def squared(x):
...   return x**2
... 
>>> pool.map(squared, range(4))
[0, 1, 4, 9]
>>> jobs.map(sqaured, range(4))
[0, 1, 4, 9]

炫耀"工人池"战略和"分散 - 聚集"向工人分配工作的策略。当然,我不会将它用于像squared这样的小工作,因为产生MPI世界的开销实际上非常高(比设置multiprocessing要高得多Pool)。但是,如果您要运行的工作量很大,就像通常使用MPI在群集上运行一样,那么pyina对您来说可能是一个很大的好处。

然而,使用pyina的真正好处是它不仅可以生成MPI的作业,而且可以将作业生成到调度程序。 pyina理解并抽象了几个调度程序的启动语法。

使用调度程序对pyina地图的典型调用如下:

>>> # instantiate and configure a scheduler
>>> from pyina.schedulers import Torque
>>> config = {'nodes'='32:ppn=4', 'queue':'dedicated', 'timelimit':'11:59'}
>>> torque = Torque(**config)
>>> 
>>> # instantiate and configure a worker pool
>>> from pyina.launchers import Mpi
>>> pool = Mpi(scheduler=torque)
>>>
>>> # do a blocking map on the chosen function
>>> pool.map(pow, [1,2,3,4], [5,6,7,8])
[1, 64, 2187, 65536]

有几种常见配置可用作预先配置的地图。 以下内容与上述示例相同:

>>> # instantiate and configure a pre-configured worker pool
>>> from pyina.launchers import TorqueMpiPool
>>> config = {'nodes'='32:ppn=4', 'queue':'dedicated', 'timelimit':'11:59'}
>>> pool = TorqueMpiPool(**config)
>>>
>>> # do a blocking map on the chosen function
>>> pool.map(pow, [1,2,3,4], [5,6,7,8])
[1, 64, 2187, 65536]

pyina需要一些TLC,因为它仍然是python2.7而且它已经在几年内没有发布......但是它已经被保留了date(在github上),否则能够完成工作"对于我在过去10年中在大型计算集群上运行工作 - 特别是与pathos结合使用时(ssh提供multiprocessing隧道和ParallelPython和{{1}的统一界面}地图)。 pyina还没有使用共享内存,但确实很好地实现了令人尴尬的功能并行计算。一般来说,与调度程序的交互非常好,但对于几种失败情况,边缘可能有点粗糙 - 而非阻塞映射需要大量工作。话虽如此,它提供了一个非常有用的界面,可以在MPI的集群上运行令人尴尬的并行作业。

在此处获取pyina(和pathos):https://github.com/uqfoundation

答案 1 :(得分:2)

有一个MPIPool类已实施here

有关我如何使用它的示例,请在GitHub上查看此gist

答案 2 :(得分:0)

我使用以下代码等同于multiprocessing.Pool。它尚未经过广泛测试,但似乎工作正常:

from functools import partial
function = partial(...)  # Store all fixed parameters this way if needed

if use_MPI:
    arguments = range(num_runs)
    run_data = None

    # mpi4py
    comm = MPI.COMM_SELF.Spawn(sys.executable, args=['MPI_slave.py'], maxprocs=num_runs)  # Init
    comm.bcast(function, root=MPI.ROOT)     # Equal for all processes
    comm.scatter(arguments, root=MPI.ROOT)  # Different for each process
    comm.Barrier()                          # Wait for everything to finish...
    run_data = comm.gather(run_data, root=MPI.ROOT)  # And gather everything up
else:        
    # multiprocessing
    p = Pool(multiprocessing.cpu_count())
    run_data = p.map(function, range(num_runs))

然后使用单独的文件'MPI_slave.py':

from mpi4py import MPI
# import the function you actually pass to this file here!!!
comm = MPI.COMM_SELF.Get_parent()
size = comm.Get_size()
rank = comm.Get_rank()

def runSlaveRun():
    function = None
    options = None
    # print("Process {}/{} reporting for duty!".format(rank, size))

    function = comm.bcast(function, root=0)
    arguments = comm.scatter(options, root=0)
    results = function(arguments)
    comm.Barrier()
    comm.gather(results, root=0)
    comm.Disconnect()

if __name__ == '__main__':
    runSlaveRun()