• MPI实现矩阵向量乘法


    (1)问题

    MPI实现矩阵向量:Ab的乘积。其中A:100行100列,b为列向量。

    (2)思路

    将所有进程分为两部分,rank=0的进程为master节点,其余进程为worker节点。

    master节点:

    (1)对A,b赋值,同时将b广播出去(这里涉及一个对广播这个函数不太熟悉的点)

    (2)对A进行划分,使其被划分为worker数量的份数,并将相应数据发送给相应的工人节点

    (3)接收工人节点的计算结果,并对收到的结果及进行一定的处理从而得到最终结果

    worker节点:

    (1)接受来自master的参数

    (2)对接收到的数据进行计算

    (3)将结果返回给master

    (3)代码

    main.cpp: 

    1. #include
    2. #include "mpi.h"
    3. #include "conf.h"
    4. #include "masterMain.h"
    5. #include "workerMain.h"
    6. #include
    7. using namespace std;
    8. MPI_Status status;
    9. int main(int argc, char *argv[]) {
    10. int size, rank;
    11. MPI_Init(&argc, &argv);
    12. char message[20];
    13. MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    14. MPI_Comm_size(MPI_COMM_WORLD, &size);
    15. int a[ROW][COL];
    16. int b[COL], res[COL]; //A为参加运算的矩阵,B为参加运算的向量,result为结果
    17. masterMain mastermain;
    18. workerMain workerMain1;
    19. if (rank == MASTER) {
    20. cout<<"进程0"<
    21. // cout << "主进程开始对矩阵和向量初始化~" << endl;
    22. for (int i = 0; i < ROW; ++i) {
    23. for (int j = 0; j < COL; ++j) {
    24. a[i][j] = 1;
    25. }
    26. b[i] = 2;
    27. }
    28. }
    29. //广播必须在主进程之外吗?(这里不太理解!!!)
    30. MPI_Bcast(&b, COL, MPI_INT, 0, MPI_COMM_WORLD);
    31. if(rank==MASTER){
    32. mastermain.matrixMuliplication(a,b,ROW,COL,size,res,status);
    33. }else{
    34. workerMain1.workerRun(a,b,ROW,COL,status);
    35. }
    36. MPI_Finalize();
    37. }

     masterMain.cpp

    1. //
    2. // Created by unbuntu-xcr on 22-10-15.
    3. //
    4. #include "masterMain.h"
    5. #include "conf.h"
    6. #include
    7. using namespace std;
    8. void masterMain::masterRun() {
    9. }
    10. /**
    11. *
    12. * @param a 矩阵A
    13. * @param b 向量b
    14. * @param row A的行数
    15. * @param col A的列数
    16. * @param size 参与运算的所有进程数
    17. * @param rank 当前进程号
    18. */
    19. void masterMain::matrixMuliplication(int a[][100], int *b, int row, int col, int size,int *res,MPI_Status status) {
    20. //master节点任务:首先是初始化矩阵,再分发矩阵,收集各个从节点返回的结果,并放到指定位置
    21. //(1)设置当前进程所需的行
    22. size = size - 1;
    23. int rowPerWorker;
    24. rowPerWorker = row / size;
    25. //master给每个进程传递数据的偏移量
    26. int offset = 0;
    27. cout << "主进程开始对数据进行分发~" << endl;
    28. for (int i = 1; i <= size; ++i) {
    29. rowPerWorker = (i <= row % size ? rowPerWorker + 1 : rowPerWorker);
    30. int count = row * rowPerWorker;
    31. //给从进程传递计算数据
    32. MPI_Send(&offset,1,MPI_INT,i,FROMMASTER,MPI_COMM_WORLD);
    33. MPI_Send(&rowPerWorker,1,MPI_INT,i,FROMMASTER,MPI_COMM_WORLD);
    34. MPI_Send(a[offset], count, MPI_INT, i, FROMMASTER, MPI_COMM_WORLD);
    35. offset+=rowPerWorker;
    36. }
    37. int result[rowPerWorker];
    38. //MASTER接收从进程发来的消息
    39. for (int i = 1; i <= size ; ++i) {
    40. int k=0;
    41. MPI_Recv(&offset,1,MPI_INT,i,FROMWORKER,MPI_COMM_WORLD,&status);
    42. MPI_Recv(&rowPerWorker,1,MPI_INT,i,FROMWORKER,MPI_COMM_WORLD,&status);
    43. MPI_Recv(result,rowPerWorker,MPI_INT,i,FROMWORKER,MPI_COMM_WORLD,&status);
    44. for (int j = offset; j <= offset+rowPerWorker ; ++j) {
    45. res[j]=result[k++];
    46. }
    47. }
    48. cout<<"矩阵向量乘结果为:"<
    49. for (int i = 0; i < col; ++i) {
    50. cout<" ";
    51. }
    52. }

     workerMain.cpp

    1. //
    2. // Created by unbuntu-xcr on 22-10-15.
    3. //
    4. #include "workerMain.h"
    5. #include "conf.h"
    6. void workerMain::workerRun(int a[][100], int *b, int row, int col,MPI_Status status) {
    7. //接收主进程传递的向量,相应矩阵,相应数据,并返回相应计算结果
    8. int offset;
    9. int rowPerWorker;
    10. //接收偏移量
    11. MPI_Recv(&offset,1,MPI_INT,MASTER,FROMMASTER,MPI_COMM_WORLD,&status);
    12. //接收行数
    13. MPI_Recv(&rowPerWorker,1,MPI_INT,MASTER,FROMMASTER,MPI_COMM_WORLD,&status);
    14. //接收矩阵A
    15. MPI_Recv(a,rowPerWorker*col,MPI_INT,MASTER,FROMMASTER,MPI_COMM_WORLD,&status);
    16. int result[rowPerWorker];
    17. // 计算
    18. for (int i = 0; i < rowPerWorker; ++i) {
    19. result[i]=0;
    20. for (int j = 0; j < col; ++j) {
    21. result[i]+=a[i][j]*b[j];
    22. }
    23. }
    24. MPI_Send(&offset,1,MPI_INT,MASTER,FROMWORKER,MPI_COMM_WORLD);
    25. MPI_Send(&rowPerWorker,1,MPI_INT,MASTER,FROMWORKER,MPI_COMM_WORLD);
    26. MPI_Send(result,rowPerWorker,MPI_INT,MASTER,FROMWORKER,MPI_COMM_WORLD);
    27. }

    (4)总结

    1)为什么要分这么多CPP文件来写?因为想熟悉c++在工程结构上的写法,所以要慢慢开始以这种写法来写

    2)问题:mpi_bcast()函数放在master判断条件内为什么就不能将值广播出去?

    3)注意:写的时候,先写master发送的,然后写worker接收相应的值,在其进行一定处理并发送给master后,再在master中写接受到相应值之后的操作,这样不至于逻辑混乱

    4)还要注意:send和recv必须保持顺序一致,send谁在前,那么接收谁就在前,不然就会出错

  • 相关阅读:
    JAVA社区疫情防控系统毕业设计,社区疫情防控管理系统设计与实现,毕设作品参考
    根据PPG估算血压利用频谱谱-时间深度神经网络【翻】
    Golang中init()函数初始化顺序
    文件上传下载
    小米 vivo oppo 等mtk芯片机型线刷授权的分析描述 免授权操作
    栈和队列oj题
    黑寡妇(BWO)优化算法(Matlab代码实现)
    【从Python基础到深度学习】 8. VIM两种状态
    机器学习面试准备(一)KNN
    【C++】map & set 底层刨析
  • 原文地址:https://blog.csdn.net/jaaccck/article/details/127412709