我使用多处理池在Python中运行并行仿真,并且在具有多个核心的计算机中运行良好。现在我想使用多个节点在集群上执行程序。我想多处理不能应用于分布式内存。但mpi4py似乎是个不错的选择。那么这些代码最简单的mpi4py等价是什么:
from multiprocessing import Pool
pool = Pool(processes=16)
pool.map(functionName,parameters_list)
答案 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)
答案 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()