如题:

最近在看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. Python基础——上节补充及数据类型

    1.变量的创建过程 当我们创建一个变量name='oldboy'时,实际上是这样一个过程. 程序先开辟了一个内存空间,把变量的内容放进去,再让变量name指向'oldboy'所在的内存地址. 我们可以 ...

  2. git与gitee码云

    1.git分支 在前面我们基本了解Git的使用方法,这一节我们看下GIt重要概念[分支] 背景 例如于超老师在开发一个同性交友网站,刚写到登录功能,代码还没写完,今天先睡觉了,所以就commit提交到 ...

  3. 3个月搞定计算机二级C语言!高效刷题系列进行中

    前言 大家好,我是梁国庆. 计算机二级应该是每一位大学生的必修课,相信很多同学的大学flag中都会有它的身影. 我在大学里也不止一次的想要考计算机二级office,但由于种种原因,备考了几次都不了了之 ...

  4. python logger 打印日志错误行数

    python logger 打印日志错误行数 import logging app = Flask(__name__) # 配置日志 handler = logging.FileHandler('ap ...

  5. Luban小试牛刀

    Luban小试牛刀 LubanUnity LubanUnity配置工具配置解决方案 简介 Github  文档   视频教程  Unity工具 个人感觉挺强大,便捷的,适合中大型游戏项目的配置工作.小 ...

  6. STM32 CubeMX 学习:05-串口

    --- title: mcu-stm32-cube-05-using-serial.md date: 2020-03-09 10:37:34 categories: tags: - stm32 - c ...

  7. python基础-入门必备知识

    1 标识符 标识符是编程时使用的名字,用于给变量.函数.语句块等命名,Python 中标识符由字母.数字.下划线组成,不能以数字开头,区分大小写. 以下划线开头的标识符有特殊含义,单下划线开头的标识符 ...

  8. Spring的三种依赖注入的方式

    1.什么是依赖注入 依赖注入(Dependency Injection,简称DI),是IOC的一种别称,用来减少对象间的依赖关系. 提起依赖注入,就少不了IOC. IOC(Inversion of C ...

  9. ORACLE 如何判断某字段是否小于0

    Oracle 自带的函数 SIGN 表达式的正 (+1).零 (0) 或负 (-1) 号 SQL> SELECT SIGN(-47.3), SIGN(0), SIGN(47.3) FROM du ...

  10. SpringBoot 1.x 2.x配置文件指定服务项目名

    SpringBoot版本1.x: server.context-path=/demo SpringBoot版本2.x: server.servlet.context-path=/demo