之前一直想写一个关于MPI的例子,之后便想起了矩阵相乘,之后便在网上找资料,结果发现有些地方实现不了,于是便自己参考网上例子,踩了各种各样的雷之后于是才有了这次分享
1.MPI并行运算的思想
MPI并行运算通过由用户指定分配进程,来实现多进程的一种思想。MPI(Message-Passing-Interface 消息传递接口)实现并行是进程级别的,通过通信在进程之间进行消息传递。MPI并不是一种新的开发语言,它是一个定义可以被C、C++和Fortran程序调用的函数库。这些函数库里面主要涉及的是两个进程之间通信的函数。MPI可以在Windows和linux环境中都有相应的库,本篇以Windows10作为演示开发环境。
2.配置MPI环境
Windows为了兼容MPI,自己做了一套基于一般个人电脑的MPI实现。如果要安装正真意义上的MPI的话,请直接去www.mpich.org下载,里面根据对应的系统下载相应的版本。
安装 mpi
我的电脑是64位的,所以安装的是 mpi_x64.msi ,默认安在C:\Program Files\Microsoft HPC Pack 2008 R2,在此,为了之后调试代码方便,最好设置一下环境变量:在用户变量PATH中,加入:C:\Program Files\Microsoft HPC Pack 2008 R2\Bin\。
配置mpi
配置目录,即加载Include和Lib库
加载依赖项
3.编译
根据编程员的习俗先从一个helloworld开始
#include "mpi.h"
#include
int main(int argc, char* argv[])
{
int rank, numproces;
int namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);//获得进程号
MPI_Comm_size(MPI_COMM_WORLD, &numproces);//返回通信子的进程数
MPI_Get_processor_name(processor_name, &namelen);
fprintf(stderr, "hello world! process %d of %d on %s\n", rank, numproces, processor_name);
MPI_Finalize();
return 0;
}
4.mpi 矩阵相乘
接下来便开始我们的主题
实际的思想是使用0进程将矩阵切分成n份分别发送个其他的进程,再有其他的进程计算完成之后再发回0进程。
0进程进行分发,切分,以及整合矩阵。
if (myid == 0) {
int **N = NULL;
int *buffer3 = nullptr;
cout << "输入你的值" << endl;
cin >> am;
start2 = MPI_Wtime();
//将am的值广播给每一个进程(除了0进程)
for (int i = 0; i < size; i++) {
MPI_Send(&am, 1, MPI_INT, i + 1, 33, MPI_COMM_WORLD);
}
/*
新建矩阵并初始化
*/
srand((unsigned)time(NULL));
buffer3 = (int*)malloc(sizeof(int)*am);
int* M = new int[am*am];
cout << "-------A类矩形------" << endl;
for (int i = 0; i < am; i++) {
for (int j = 0; j < am; j++) {
M[i*am + j] = (rand() % 9) + 1;
cout << M[i*am + j] << " ";
}
cout << endl;
}
N = (int**)malloc(sizeof(int)*am);
for (int i = 0; i < am; i++) {
N[i] = (int*)malloc(sizeof(int)*am);
}
cout << "-------B类矩形------" << endl;
for (int i = 0; i < am; i++) {
for (int j = 0; j < am; j++) {
N[i][j] = (rand() % 9) + 1;
cout << N[i][j] << " ";
}
cout << endl;
}
/*
判断是否采用单线程
*/
if (numprocs
//接受来自0进程的值
if (myid != 0) {
MPI_Recv(&am, 1, MPI_INT, 0, 33, MPI_COMM_WORLD, &status);
}
if (myid != 0 && myid <= am && numprocs>am) {
int temp;
int buffer2, m;
int buffer = new int[amam];
buffer2 = (int)malloc(sizeof(int)am);
m = (int)malloc(sizeof(int)am);
/
接受来自0进程的数据
/
MPI_Recv(buffer2, am, MPI_INT, 0, 11, MPI_COMM_WORLD, &status);
MPI_Recv(buffer, amam, MPI_INT, 0, 22, MPI_COMM_WORLD, &status);
for (int i = 0; i < am; i++) {
m[i] = 0;
temp = 0;
for (int j = 0; j < am; j++) {
temp = +buffer[jam + i] * buffer2[j];
}
m[i] = temp;
}
/*
将得到的数据进行计算并且将其传回0进程
*/
MPI_Send(m, am, MPI_INT, 0, myid, MPI_COMM_WORLD);
free(buffer);
free(buffer2);
free(m);
}
在这里我也将头部添上
#include
#include
#include
#include"mpi.h"
#include
#include
#pragma comment(lib,"msmpi.lib")
using namespace std;
int am;
int main(int argc, char **argv) {
int numprocs;
int myid, size;
MPI_Status status;
double start1, start2, end;
MPI_Init(&argc, &argv);//MPI Initialize
MPI_Comm_rank(MPI_COMM_WORLD, &myid);//获得当前进程号
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);//获得进程个数
size = numprocs - 1;
尾部添上
MPI_Finalize();
return 0;
}