好了这次叫我们来看看什么是mpi。

那好了,让我们来以一张图来看看它到底是个什么东西吧。


这里其实我们不难发现,对于串行而言,内存与CPU处理器之间是相连的,但是,对于mpi而言,对每一个处理器,都是有各自的内存,不过它们之间可以通过网络的方式连接起来,构成共享。
再来介绍介绍,使用mpi不可或缺的调用接口吧,来看看万能的度娘怎么解释的。
1.mpi init初始化MPI执行环境,建立多个MPI进程之间的联系,为后续通信做准备
2.mpi finalize结束MPI执行环境
3.mpi comm rank用来标识各个MPI进程的,给出调用该函数的进程的进程号,返回整型的错误值。两个参数:MPI_Comm类型的通信域,标识参与计算的MPI进程组; &rank返回调用进程中的标识号;
4.mpi comm size用来标识相应进程组中有多少个进程
5.mpi send(buf,counter,datatype,dest,tag,comm): buf:发送缓冲区的起始地址,可以是数组或结构指针;count:非负整数,发送的数据个数;datatype:发送数据的数据类型;dest:整型,目的的进程号;tag:整型,消息标志;comm:MPI进程组所在的通信域
含义:向通信域中的dest进程发送数据,数据存放在buf中,类型是datatype,个数是count,这个消息的标志是tag,用以和本进程向同一目的进程发送的其它消息区别开来
6.mpi recv(buf,count,datatype,source,tag,comm,status): source:整型,接收数据的来源,即发送数据进程的进程号; status:MPI_Status结构指针,返回状态信息

好的,看完上面的介绍,我们来一起看看这程序要如何写是好呢。
先让我们来纠正一个很多时候初学者易犯的错误。看看下图,大家一开始的反应估计都是,这还用讲?不就是Init和Finalize是串行,内是并行吗,有什么值得说的?
好,问题来了。
Q:这个串行他是怎么个意义上的串行呢?
A:代码是被copy到所有并行进程的,所以在Init和Finalize外也会被所有的进程全部执行一次。可以试着输出一下my_rank,就可以看出区别了。
那么这告诉我们要小心什么呢?
小心内存咯,不要把一个共享的内存让每个进程都自己开——一——遍——啊——!

好滴,继续继续!我们想要进行进程间通信,没有通信接口,可怎么办啊,这可不行啊
程序猿想找对象,但是你发现没有传递心意的对象,哪找p啊。快来看看怎么传递吧。
什么?你有对象了,那没事了(我什么时候也能有呢嘤嘤嘤)。那就看看怎么传递消息吧。



注意,这里标签的使用也很关键,不可或缺啊!

当然了,写这种并行程序的时候也一定要注意死锁,千万不要出现这种情况,互相等待实在太痛苦了(怎么又好像回到搞对象的话题了)。

那么言归正传,程序要怎么写呢?
首先你可能要定义一系列可能用到的变量,然后开始Init进入到并行区域,获取进程个数和自己的PID,然后开一个矩阵,然后初始化确定规模和初值(前面提到了,在哪里初始化不言而喻了吧),然后将对应信息在进程间传递并让每个进程自己转置自己的部分再把最终信息汇总即可。

#include <stdio.h>
#include <malloc.h>
#include <cmath>
#include <cstdlib>
#include "mpi.h"
int **matrix, **out, *tmp;//输入输出矩阵,传递时候的临时变量
int n;
double t_start, t_end;
MPI_Status status;void init(){matrix = (int **)malloc(n * sizeof(int *));out = (int **)malloc(n * sizeof(int *));for(int i=0;i<n;i++){matrix[i] = (int *)malloc(n * sizeof(int));out[i] = (int *)malloc(n * sizeof(int));}
}void getValue(){int cnt = 0;for(int i=0;i<n;i++){for(int j=0;j<n;j++){matrix[i][j] = out[i][j] = cnt;cnt++;}}
}void print(){for(int i=0;i<n;i++){for(int j=0;j<n;j++){printf("%d ",out[i][j]);}printf("\n");}
}int main(int argc, char *argv[]){//矩阵维数 n = atoi(argv[1]);int my_rank,group_size;int sqrt_group_size,u,v,length;//进程数开根号即每行或每列的子块数,列号,行号,每个块的维数 //init之前不是简单的想象中并行,这里对于每个进程而言都是串行执行了一下 //开始并行程序 MPI_Init(&argc, &argv);//获取进程数 MPI_Comm_size(MPI_COMM_WORLD,&group_size);//获取PID MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);sqrt_group_size = sqrt(group_size);u = my_rank%sqrt_group_size;v = my_rank/sqrt_group_size;length = n/sqrt_group_size;tmp = (int *)malloc(sizeof(int)*length*length);if(my_rank == 0){//0号进程对矩阵初始化,不知道为什么放在并行化外初始化会段错误init();getValue();t_start = MPI_Wtime();//这两层循环是找到对应编号的子块for(int i=0;i<sqrt_group_size;i++){for(int j=0;j<sqrt_group_size;j++){//这里该确定每一个子块中的元素对应在matrix里的位置了 //貌似传递的数据需存在一维数组中,二维可能存在内存不连续的状况int point = 0;for(int k=length*i;k<length*(i+1);k++){for(int l=length*j;l<length*(j+1);l++){tmp[point] = matrix[k][l];point++;}}//0号子块由0号进程自己转置if(i==0 && j==0){for(int i=0;i<length;i++){for(int j=0;j<length;j++){out[i][j] = matrix[j][i];}}}//其他子块送到其他进程中去转置 else{MPI_Send(tmp,length*length,MPI_INT,i*sqrt_group_size+j,i*sqrt_group_size+j,MPI_COMM_WORLD);}}}}else{//printf("myrank=%d\n",my_rank);MPI_Recv(tmp,length*length,MPI_INT,0,my_rank,MPI_COMM_WORLD,&status);//printf("myrank %d receive 0 successfully\n",my_rank);//内部转置 int t;for(int i=0;i<length;i++){for(int j=i+1;j<length;j++){t = tmp[i*length+j];tmp[i*length+j] = tmp[j*length+i];tmp[j*length+i] = t;}}MPI_Send(tmp,length*length,MPI_INT,0,my_rank,MPI_COMM_WORLD);}if(my_rank==0){//还是先找每一个子块对应的进程 for(int i=0;i<sqrt_group_size;i++){for(int j=0;j<sqrt_group_size;j++){if(i!=0 || j!=0){//printf("0 receive myrank=%d\n",i*sqrt_group_size+j);MPI_Recv(tmp,length*length,MPI_INT,i*sqrt_group_size+j,i*sqrt_group_size+j,MPI_COMM_WORLD,&status);//printf("0 receive myrank=%d successfully\n",i*sqrt_group_size+j);for(int x=0;x<length;x++){for(int y=0;y<length;y++){//要交换的子块进行交换 out[j*length+x][i*length+y] = tmp[x*length+y];}}}}}t_end = MPI_Wtime();printf("Matrix order:%d, Time cost:%lf\n",n,t_end-t_start);print();free(matrix);}free(tmp);MPI_Finalize();return 0;
}

结果如下,

0 10 20 30 40 50 60 70 80 90
1 11 21 31 41 51 61 71 81 91
2 12 22 32 42 52 62 72 82 92
3 13 23 33 43 53 63 73 83 93
4 14 24 34 44 54 64 74 84 94
5 15 25 35 45 55 65 75 85 95
6 16 26 36 46 56 66 76 86 96
7 17 27 37 47 57 67 77 87 97
8 18 28 38 48 58 68 78 88 98
9 19 29 39 49 59 69 79 89 99

好了,到这里这篇文章就结束了,希望大家能有所收获,也希望能指出我的不足,共同进步。

并行计算mpi实现矩阵转置,mpi分布式编程简介,点对点通信方法相关推荐

  1. 【Flutter】Future 异步编程 ( 简介 | then 方法 | 异常捕获 | async、await 关键字 | whenComplete 方法 | timeout 方法 )

    文章目录 一.Future 简介 二.Future.then 使用 三.Future 异常捕获 四.Dart 练习网站 五.async.await 关键字 六.whenComplete 方法 七.ti ...

  2. 【HNU分布式与云计算系统】MPI实现矩阵乘矩阵运算

    MPI实现矩阵乘矩阵运算 实验环境 操作系统:Ubuntu 20.04 编程语言:C++ 实验原理 什么是MPI MPI是一个跨语言的通讯协议,用于编写并行计算机.支持点对点和广播.MPI是一个信息传 ...

  3. C语言链表的转置算法,c语言编程集 数据结构 顺序表 点链表 数制转换 矩阵转置.doc...

    c语言编程集 数据结构 顺序表 点链表 数制转换 矩阵转置 #include "stdio.h" #include "malloc.h" /*typedef s ...

  4. 经典编程习题,用Java实现:矩阵转置、最大公约数和最小公倍数、计算自然对数的底e的值、输出1000以内的回文素数、判断两个年份之间的平闰年情况。

    经典编程习题,用Java实现 1.矩阵转置 2.最大公约数和最小公倍数 3.计算自然对数的底e的值 4.输出1000以内的回文素数 5.判断两个年份之间的平闰年情况 1.矩阵转置 public cla ...

  5. MPI实现矩阵向量乘法

    (1)问题 MPI实现矩阵向量:Ab的乘积.其中A:100行100列,b为列向量. (2)思路 将所有进程分为两部分,rank=0的进程为master节点,其余进程为worker节点. master节 ...

  6. OpenCV 1.x 2.x 编程简介(矩阵/图像/视频的基本读写操作)

    OpenCV 编程简介(矩阵/图像/视频的基本读写操作) Introduction to programming with OpenCV OpenCV编程简介 作者: Gady Agam Depart ...

  7. 使用VS2019+Intel OneAPI (ifort)+Intel MPI编译和运行MPI程序与Coarray程序

    使用VS2019+Intel OneAPI (ifort)+Intel MPI编译和运行MPI程序与Coarray程序 一.安装环境 安装vs2019 安装Intel OneAPI Base Tool ...

  8. [MATLAB技术贴]漫谈MATLAB矩阵转置

    矩阵转置是matlab最基本的操作了,但这个基本操作,也是很多初学者容易出现问题的地方.本帖通过几个实例演示matlab矩阵转置的操作. 方法一:'  运算符与  .'  运算符 >>a ...

  9. 真题演练-M*N矩阵转置

    题目:编程计算并输出m*n阶矩阵的转置矩阵.其中,m和n的值由用户用键盘输入.已知m和n的值都不超过10. 解法1:用二维数据作为函数参数,实现矩阵转置 #include <stdio.h> ...

最新文章

  1. NSAssert和NSLog
  2. 5G URLLC — Overview
  3. 进程线程005 SwapContext函数分析
  4. android studio failed to open zip file,Android Studio出现Failed to open zip file问题的解决方法...
  5. java.util.zip.ZipException: error in opening zip file
  6. 【渝粤题库】国家开放大学2021春2321物流学概论题目
  7. 白话经典算法系列之中的一个 冒泡排序的三种实现
  8. 关于ASCII字符的那些事儿
  9. 【Android】ArcFaceDemo
  10. vue-cli 里axios的使用
  11. HDU 6321(状压dp)
  12. Atitit 界面接口技术 cli gui nui cui管理 attilax总结 1. NUI 1 1.1. 问:什么是“自然用户界面”? 1 2. Cli到gui到nui CUI 2 2.1.
  13. robocode java_IBM Robocode Java学习利器(1)Robocode 入门
  14. android 教程 百度云盘,【从零教程】带你从零编写自己的在线百度云盘 11-21更新...
  15. Dlib库实现人脸关键点检测(Opencv实现)
  16. 指针的指针(简单易懂)
  17. 2021碳纤维山地车哪个牌子好世界10大顶级自行车品牌排行榜
  18. 我们公司没销售 - 疫情下企业软件的互联网营销
  19. Oracle 数据库表空间容量调整(表空间缩容脚本)脚本
  20. STM32 VCP PC端安装驱动失败的问题解决

热门文章

  1. gstreamer教程(一)-基本概念
  2. 图像特征之SURF特征匹配
  3. C# 调用Everything查找文件
  4. sql 转换 不足位数补0
  5. KNN分类——matlab(转载)
  6. (一)Deep learning论文纯翻译
  7. 2022-2028全球与中国员工时间管理系统市场现状及未来发展趋势
  8. jmeter获取token并请求失败Internal authentication failed 400
  9. clk_mux及对应的约束
  10. 企业搬迁至直线50公里新地点,员工不去被要求集中办理离职,请各位大佬支招如何保证自身权益?