如题:

最近在看MPI4PY的代码,但是发现这东西除了编写简洁外(少量代码实现复杂的多进程通信,包括单机和多机),好像也没有别的太多功能,当然MPI本身在多机通信广播、规约上做的很成熟,但是假设我们只是在一个单机上来运行Python多进程代码,那么使用MPI4PY除了代码简洁上以外在运行性能上是否会有区别呢???

本文探讨的主题就是如果我不使用分布式运行代码,而只是使用单机运行多进程代码,那么除了编码简洁外,MPI编程是否会有性能上的优势。

本文采用几个代码来探讨这个问题:本文代码为多子进程操作父进程中的一段内存,每次操作都将该内存中数据自加一。

给出第一个代码,纯Python实现,不使用MPI的情况下在单机运行多进程:

import ctypes
import time
import multiprocessing
import numpy as np #NUM_PROCESS = multiprocessing.cpu_count()
NUM_PROCESS = 4 size = 1000000 def worker(index):
main_nparray = np.frombuffer(shared_array_base[index], dtype=ctypes.c_double)
for i in range(10000):
main_nparray[:] = index + i
return index if __name__ == "__main__":
shared_array_base = []
for _ in range(NUM_PROCESS):
shared_array_base.append(multiprocessing.Array("d", size, lock=False)) pool = multiprocessing.Pool(processes=NUM_PROCESS) a = time.time()
result = pool.map(worker, range(NUM_PROCESS))
b = time.time()
print(b-a)
#print(result) for i in range(NUM_PROCESS):
main_nparray = np.frombuffer(shared_array_base[i], dtype=ctypes.c_double)
print(main_nparray)
print(type(main_nparray))
print(main_nparray.shape)

第二个代码,使用MPI4PY,多非root进程每一次操作都进行同步,root进程与非root进程通信采用分发和收集操作。

from mpi4py import MPI
import numpy as np
import time comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size() recv_data = np.zeros(1000000, dtype=np.double) send_data = None
if rank == 0:
send_data = np.zeros((size, 1000000), dtype=np.double)
send_data[1]+=1
send_data[2]+=2
send_data[3]+=3 if rank ==0:
a=time.time()
for i in range(10000): comm.Scatter(send_data, recv_data, root=0) #if rank != 0:
# recv_data += 1
recv_data += 1 comm.Gather(recv_data, send_data, root=0)
if rank ==0:
b=time.time()
print(send_data)
print(b-a)

第三个代码,同样使用MPI4PY,多非root进程每一次操作都不进行同步,root进程与非root进程通信采用点对点方式,并且root进程与非root进程同样使用异步操作。

from mpi4py import MPI
import numpy as np
import time comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size() recv_data = np.zeros(1000000, dtype=np.double) send_data = None
if rank == 0:
send_data = np.zeros((size-1, 1000000), dtype=np.double)
send_data[0]+=0
send_data[1]+=1
send_data[2]+=2
send_data[3]+=3 if rank == 0:
a, b, c, d = 10000, 10000, 10000, 10000
a_one_finish = True
b_one_finish = True
c_one_finish = True
d_one_finish = True a_time = time.time()
while True:
if a != 0:
if a_one_finish == True:
a_one_finish == False
a_req = comm.Isend(send_data[0], dest=1)
a_req2 = comm.Irecv(send_data[0], source=1)
a_one_finish = a_req2.test()[0]
if a_one_finish==True:
a -= 1
else:
a_one_finish = a_req2.test()[0]
if a_one_finish==True:
a -= 1 if b != 0:
if b_one_finish == True:
b_one_finish == False
b_req = comm.Isend(send_data[1], dest=2)
b_req2 = comm.Irecv(send_data[1], source=2)
b_one_finish = b_req2.test()[0]
if b_one_finish==True:
b -= 1
else:
b_one_finish = b_req2.test()[0]
if b_one_finish==True:
b -= 1 if c != 0:
if c_one_finish == True:
c_one_finish == False
c_req = comm.Isend(send_data[2], dest=3)
c_req2 = comm.Irecv(send_data[2], source=3)
c_one_finish = c_req2.test()[0]
if c_one_finish==True:
c -= 1
else:
c_one_finish = c_req2.test()[0]
if c_one_finish==True:
c -= 1 if d != 0:
if d_one_finish == True:
d_one_finish == False
d_req = comm.Isend(send_data[3], dest=4)
d_req2 = comm.Irecv(send_data[3], source=4)
d_one_finish = d_req2.test()[0]
if d_one_finish==True:
d -= 1
else:
d_one_finish = d_req2.test()[0]
if d_one_finish==True:
d -= 1 if a+b+c+d ==0:
break b_time = time.time()
print(b_time-a_time)
print(send_data) if rank != 0:
for _ in range(10000):
comm.Recv(recv_data, source=0)
recv_data += 1
comm.Send(recv_data, dest=0)
#print(recv_data)

注意:由于采用了点对点异步通信的方式,因此代码3中将总共运行的进程数些死了,只能运行5个进程,其中非root进程为4个。

===================================================

测试平台1:Xeon CPU: 24物理核心,48逻辑核心

代码1:运行时间:4.73 秒

代码2:运行时间:144.68 秒

代码3:运行时间:140.43 秒

测试平台2:i7 8代台式机CPU: 6物理核心,12逻辑核心

代码1:运行时间:16.05 秒

代码2:运行时间:80.61 秒

代码3:运行时间:84.24 秒

特别说明:

从上面的结果我们可以看到代码2的性能会比代码3的性能好一些,不过考虑到运行的误差性,我们可以把代码2与代码3的运行时间看做相当(几乎相同)。

其中,

代码2的运行命令为:mpirun -np 4   python x2.py

代码3的运行命令为:mpirun -np 5   python x3.py

在平台1上之所以代码1性能最好主要是因为在消息传递不是主要影响性能的因素时计算性能主要受向量计算能力所影响,而平台1的向量计算能力要优于平台2,因此平台1上代码1的性能最好。

平台1上之所以代码2,代码3的性能最差是因为当消息传统为性能主要影响因素时平台1的内存数据的传递速度要慢于平台2。

补充:共享内存的方式时多进程间消息传递几乎是不损耗时间的,几乎如在自身进程的内存空间中操作一样。

===================================================

从上面的计算结果可以推断出即使在单机情况下MPI编码的多进程通信也并不是采用共享内存的方式,而是进程间内存拷贝的方式,所以我们可以知道在单机情况下MPI编程的代码在消息传递方面并不占优势,只能说性能适合,其性能还是比不上手动编写的共享内存通信方式的性能。

呼应开篇之说,

本文探讨的主题就是如果我不使用分布式运行代码,而只是使用单机运行多进程代码,那么除了编码简洁外,MPI编程是否会有性能上的优势。

答案就是:

只使用单机运行多进程代码,那么除了编码简洁外(快速编程外),MPI编程并不会有性能上的优势。

总结一下:

MPI的优势:

使用MPI可以便捷的编写多进程代码,编写较为容易的将单进程代码改写为多进程代码。

或者说,MPI的优势是可以快速的在多机的分布式平台环境下运行,具有较好的扩充性,比较典型的应用场景就是在超算中心的超算平台上计算流体动力学这样的数值计算任务。比较MPI的代码可以很好的在上百台服务构成的计算环境中运行,而这种计算场景我们如果不使用MPI编程而是手动去编写代码去实现消息通信,那不仅工作量巨大,而且性能难以保证,甚至可能是一个不太可能实现的工作。

因此,如果你打算要你的代码(数值计算任务)以后在多机环境下(众多服务器环境,不太指那种两台,三台服务器环境)分布式运行那么MPI是你很好的选择,或者说是你唯一的选择,但是如果你就一台服务器,而且未来也不太可能有大集群服务器运行的可能,那么mpi编程并没有什么优势,或者说至少不是第一选择,也不是第二选择,或者说你不会别的并行通信方式的编码而只会mpi那么你选mpi编程完全OK。

参考:

https://materials.jeremybejarano.com/MPIwithPython/#

在单机条件下,MPI4PY与纯Python多进程代码来比较是否有性能优势???的更多相关文章

  1. 如何在已安装Python条件下,安装Anaconda,,并将原有Python添加到Anaconda中

    在安装Anaconda之前,有的已经安装过一个Python版本了,但是又不想删除这个Python版本,该怎么办呢? 概括:轻松两步--在系统环境变量中找到对应之前安装Python的路径并删除:直接将你 ...

  2. 《Python CookBook2》 第四章 Python技巧 - 若列表中某元素存在则返回之 && 在无须共享引用的条件下创建列表的列表

    若列表中某元素存在则返回之 任务: 你有一个列表L,还有一个索引号i,若i是有效索引时,返回L[i],若不是,则返回默认值v 解决方案: 列表支持双向索引,所以i可以为负数 >>> ...

  3. 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!

    本文参考:http://www.dabeaz.com/coroutines/   作者:David Beazley 缘起: 本人最近在学习python的协程.偶然发现了David Beazley的co ...

  4. 机器学习之线性回归(纯python实现)][转]

    本文转载自:https://juejin.im/post/5a924df16fb9a0634514d6e1 机器学习之线性回归(纯python实现) 线性回归是机器学习中最基本的一个算法,大部分算法都 ...

  5. 虚拟机在 OpenStack 里没有共享存储条件下的在线迁移

    虚拟机在 OpenStack 里没有共享存储条件下的在线迁移 本文尝试回答与 Live migration 相关的几个问题:Live migration 是什么?为什么要做 Live migratio ...

  6. 是AI就躲个飞机-纯Python实现人工智能

    你要的答案或许都在这里:小鹏的博客目录 代码下载:Here. 很久以前微信流行过一个小游戏:打飞机,这个游戏简单又无聊.在2017年来临之际,我就实现一个超级弱智的人工智能(AI),这货可以躲避从屏幕 ...

  7. 纯python自研接口自动化脚本更新版本,让小白也能实现0到1万+的接口自动化用例

    查看完整文章点击原文链接:纯python自研接口自动化脚本更新版本,让小白也能实现0到1万+的接口自动化用例 你是否还在用postman\jmeter做接口自动化吗?用python的开源框架[unit ...

  8. django之分页,纯python代码

    Django中分页 py文件代码 """ 自定义分页组件 可以返回分页的数据和分页的HTML代码 """ from django.http ...

  9. 【Redis场景4】单机环境下秒杀问题

    单机环境下的秒杀问题 全局唯一ID 为什么要使用全局唯一ID: 当用户抢购时,就会生成订单并保存到订单表中,而订单表如果使用数据库自增ID就存在一些问题: 受单表数据量的限制 id的规律性太明显 场景 ...

  10. 使用n2n在没有公网IP条件下访问树莓派

    实现:在树莓派2和客户机都没有公网IP条件下实现远程访问控制 不足:暂时没实现网页代理 因为校园网环境没有公网IP,无法直接访问树莓派.之前有想过SSH反向代理:使用VPN,ddns(花生壳.no-i ...

随机推荐

  1. 西数 WD SATA SSD 固态 蓝盘 复制和剪切速度慢

    现象:速度只有4,5M,活动时间100%.用AS SSD 测试速度正常. 问题:冷数据掉速.冷数据门. 解决方法:用DiskFresh,刷新下. 刷新时间,要看你存储数据的多少.我的1T 蓝盘,用了3 ...

  2. Python 调整PDF页面尺寸大小

    在处理PDF文件时,我们可能会遇到这样的情况:原始PDF文档不符合我们的阅读习惯,或者需要适配不同显示设备等.这时,我们就需要及时调整PDF文档中的页面尺寸,以满足不同应用场景的需求. 利用Pytho ...

  3. java堆和栈有哪些区别

    java堆和栈有哪些区别 Java堆和栈是Java虚拟机(JVM)中的两个重要概念,它们在内存管理.存储对象和执行线程等方面有明显的区别. 1.内存分配和管理Java堆是动态分配的内存区域,主要用来存 ...

  4. 使用vue-contextmenujs鼠标右键菜单时,当高度不够时显示不全的问题

    之前是采用npm或者yarn直接装包vue-contextmenujs的形式: npm install vue-contextmenujs -S || yarn add vue-contextmenu ...

  5. Linux 网络编程的5种IO模型 总结

    背景 在网络编程中,经常会用到一些模型,在这里做一下总结. 正文 Linux 网络编程的5种IO模型:阻塞IO与非阻塞IO 这是最简单的模型,一般配合多线程来实现. Linux 网络编程的5种IO模型 ...

  6. python 无监督生成模型

    无监督生成模型在机器学习中扮演着重要角色,特别是当我们在没有标签数据的情况下想要生成新的样本或理解数据的内在结构时.一种流行的无监督生成模型是生成对抗网络(Generative Adversarial ...

  7. Linux 特权 SUID/SGID 的详解

    导航 0 前言 1 权限匹配流程 2 五种身份变化 3 有效用户/组 4 特权对 Shell 脚本无效 5 Sudo 与 SUID/SGID 的优先级 6 SUID.SGID.Sticky 各自的功能 ...

  8. Nginx负载配置

    目录 Nginx 负载均衡笔记 1. 概述 1.1 Nginx 简介 1.2 负载均衡概述 2. 四层负载均衡(传输层) 2.1 工作原理 2.2 特点 2.3 优缺点 优点 缺点 2.4 示例场景 ...

  9. Linux常用指令及shell脚本记录

    记录一些常用指令在博客上,以防哪天因太久不敲而忘却,还可以直接翻看博客记录,不用再一条条百度搜...... 一.Linux常用指令 一.设置文件权限为aapp用户及用户组-- chown -R app ...

  10. c++ primer 第五版随笔

    1.what is std::endl ? for example, std::cout << "hello world" << std::endl; st ...