MPI实现矩阵相乘

之前一直想写一个关于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 <stdio.h>  

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 <am) {
   int temp;
   int **P = NULL;
   P = (int**)malloc(sizeof(int)*am);
   for (int i = 0; i < am; i++) {
    P[i] = (int*)malloc(sizeof(int)*am);
    }
 
    for (int z = 0; z < am; z++) {
    for (int i = 0; i < am; i++) {
     P[z][i] = 0;
     temp = 0;
     for (int j = 0; j < am; j++) {
      temp = +M[j*am + i] * N[z][j];
      }
     P[z][i] = temp;
    }
    }
    cout << endl;
   cout << "得到的矩阵为" << endl;
   for (int i = 0; i < am; i++) {
   for (int j = 0; j < am; j++) {
     printf("%-8d", P[i][j]);
    }
    cout << endl;
   }
   end = MPI_Wtime();
   double time = end - start2;
   cout << "单进程需要的时间为" << end - start2 << endl;
   }
  else
  {
  /*
   向各个进程发送信息
   */
   
   for (int i = 0; i < am; i++) {
    for (int j = 0; j < am; j++) {
     buffer3[j] = N[j][i];
     }
    MPI_Send(buffer3, am, MPI_INT, i + 1, 11,MPI_COMM_WORLD);
    }
    for (int i = 0; i < am; i++) {
    MPI_Send(&M[0 + 0], am*am, MPI_INT, i + 1, 22, MPI_COMM_WORLD);
   }
   free(N);
   free(buffer3);
      /*
   回收各个进程的值
   */

   int **P = NULL;
   P = (int**)malloc(sizeof(int)*am);
   for (int i = 0; i < am; i++) {
   P[i] = (int*)malloc(sizeof(int)*am);
   }
   for (int i = 0; i < am; i++) {
   MPI_Recv(&(P[i][0]), am, MPI_INT, i + 1, i + 1, MPI_COMM_WORLD, &status);
}
cout << endl;
   cout << "得到的矩阵为" << endl;
   for (int i = 0; i < am; i++) {
   for (int j = 0; j < am; j++) {
     //cout << P[i][j] << " ";
     printf("%-8d", P[i][j]);
     }
    cout << endl;
   }
     end = MPI_Wtime();
   double time = end - start2;
   cout << "多进程需要的时间为" << end - start2 << endl;
   }
 }
``

其他进程则负责接收以及计算在发送给0进程

//接受来自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, am
am, 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[j
am + 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<stdio.h>
#include<iostream>
#include<string>
#include"mpi.h"
#include <stdlib.h>
#include <time.h>
#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;
}
  • 3
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值