当我使用多处理模块和mpi4py作为通信工具测量并行应用程序的性能时,我发现了一个奇怪的效果。
该应用程序对数据集执行进化算法。除评估外,大多数操作都是按顺序完成的。在应用所有进化运算符之后,所有个体都需要接收新的适应值,这在评估期间完成。基本上它只是在浮点列表(python之类)上执行的数学计算。在评估之前,数据集由mpi的scatter或python的Pool.map分散,然后进行并行评估,之后数据通过mpi的聚集或Pool.map机制返回。
我的基准测试平台是运行Ubuntu 11.10的虚拟机(虚拟机),在Core i7(4/8内核),8 GB内存和SSD驱动器上运行Open MPI 1.4.3。
我发现真正令人惊讶的是,我获得了一个很好的加速,但是根据通信工具,在一定的进程阈值之后,性能变得更糟。它可以通过下面的图片来说明。
y轴 - 处理时间
x轴 - 进程的nr
颜色 - 每个人的大小(浮动的nr)
1)使用多处理模块 - Pool.map
2)使用mpi - Scatter / Gather
3)两张照片都在彼此之上
起初我认为它是超线程的错误,因为对于大型数据集,它在达到4个进程(4个物理内核)后变得更慢。但是它应该在多处理情况下也可见,而事实并非如此。我的另一个猜测是mpi通信方法的效率远低于python通信方法,但我觉得很难相信。
有没有人对这些结果有任何解释?
增加:
我开始相信它毕竟是超线程故障。我在具有核心i5(2/4核心)的机器上测试了我的代码,并且在3个或更多进程中性能更差。我想到的唯一解释是,我使用的i7没有足够的资源(缓存?)来与超线程同时计算评估,需要安排4个以上的进程在4个物理核上运行。
然而有趣的是,当我使用mpi htop显示所有8个逻辑核心的完全利用时,这应该表明上述语句是不正确的。另一方面,当我使用Pool.Map时,它并没有完全利用所有核心。它使用一个或2个最大值而其余部分仅使用部分,再次不知道它为什么会这样。明天我会附上一个显示此行为的屏幕截图。
我没有在代码中做任何花哨的东西,它真的很简单(我不是因为它是秘密而不是因为它是秘密的,但是因为它需要安装像DEAP这样的其他库。如果有人真正感兴趣的话问题并准备安装DEAP我可以准备一个简短的例子)。 MPI的代码有点不同,因为它无法处理填充容器(从列表继承)。当然有一些开销,但没什么大不了的。除了我在下面显示的代码之外,其余部分是相同的。
Pool.map:
def eval_population(func, pop):
for ind in pop:
ind.fitness.values = func(ind)
return pop
# ...
self.pool = Pool(8)
# ...
for iter_ in xrange(nr_of_generations):
# ...
self.pool.map(evaluate, pop) # evaluate is really an eval_population alias with a certain function assigned to its first argument.
# ...
MPI - 分散/聚集
def divide_list(lst, n):
return [lst[i::n] for i in xrange(n)]
def chain_list(lst):
return list(chain.from_iterable(lst))
def evaluate_individuals_in_groups(func, rank, individuals):
comm = MPI.COMM_WORLD
size = MPI.COMM_WORLD.Get_size()
packages = None
if not rank:
packages = divide_list(individuals, size)
ind_for_eval = comm.scatter(packages)
eval_population(func, ind_for_eval)
pop_with_fit = comm.gather(ind_for_eval)
if not rank:
pop_with_fit = chain_list(pop_with_fit)
for index, elem in enumerate(pop_with_fit):
individuals[index] = elem
for iter_ in xrange(nr_of_generations):
# ...
evaluate_individuals_in_groups(self.func, self.rank, pop)
# ...
已添加2: 正如我之前提到的,我在i5机器上进行了一些测试(2/4核心),结果如下:
我还发现了一台2 xeon(2x 6/12核心)的机器并重复了基准测试:
现在我有3个相同行为的例子。当我在比物理内核更多的进程中运行计算时,它开始变得更糟。我相信这是因为由于缺乏资源,同一物理核心上的进程无法同时执行。
答案 0 :(得分:6)
MPI实际上是为了进行节点间通信而设计的,因此可以通过网络与其他机器通信。 与例如MPI相比,在同一节点上使用MPI可能导致每个必须发送的消息的开销很大。螺纹。
mpi4py为每条消息制作一份副本,因为它针对的是分布式内存使用情况。 如果您的OpenMPI未配置为使用sharedmemory进行内部节点通信,则此消息将通过内核的tcp堆栈发送,然后返回,以便传递给另一个进程,这将再次增加一些开销。
如果您只打算在同一台机器上进行计算,则无需在此处使用mpi。
其中一些内容已经讨论in this thread.
<强>更新强> ipc-benchmark项目试图弄清楚不同通信类型在不同系统上的表现。 (多核,多处理器,共享内存)尤其是它如何影响虚拟化机器!
我建议在虚拟机上运行ipc-benchmark,然后发布结果。 如果它们看起来像this基准测试,它可以让您深入了解tcp,套接字和管道之间的区别。