并行计算练习之矩阵转置(mpi)

并行算法

    棋盘分块,先块内转置,然后在块之间进行转置。用mpi多进程实现,每个进程分配一个棋盘块,主进程进行初始化矩阵,按棋盘块顺序将数据存储到缓冲区一维数组buf中。

size是进程个数,n*n是n维矩阵,n*n /size是每个块的个数,开根号就是每个块的行或列数,而size开根号就是n行或列有多少个块。

我之前一直在想,你主进程把数据send到子进程,以及子进程将数据处理好后又send到主进程,主进程recv时怎么确保它recv的顺序呢?是先接收rank1还是rank2?

利用两个for循环,依次遍历每个棋盘块,而每个进程分配了一个棋盘块,我们指定将棋盘块顺序分配给各进程(如:第一个块分给进程0,第二块分给进程1,以此类推)

好像也可以用mpi_scatter和mpi_gather来传递信息?

参考:并行计算mpi实现矩阵转置,mpi分布式编程简介,点对点通信方法_結城的博客-CSDN博客n

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include<mpi.h>
#include<math.h>
int **a,*b,**result;             //全局变量
MPI_Status status;


void init_matrix(int n)        //初始化矩阵
{
    a = (int**)malloc(n * sizeof(int*));
    result = (int **)malloc( n * sizeof(int) );

    for(int i = 0; i < n; i++)
        {
            a[i] = (int*)malloc(n * sizeof(int));
            result[i] = (int *)malloc( sizeof(int) * n );
        }
    int b = 0;

    for(int i = 0; i < n; i++)
   {
      for(int j = 0; j < n; j++)
        {
            a[i][j] = b;
            result[i][j] =b;
            b++;
            printf("%2d ", a[i][j]);
        }
        printf("\n");
   }

}

int main(int argc, char **argv)
{
int n = 6;

MPI_Init(NULL,NULL);
double t1 = MPI_Wtime();
int rank,size;

MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);

int each_row_has_block = sqrt(size);   //矩阵是n*n,表示行或列有多少个block
int block_size =  n / each_row_has_block;   // 每个block的size
b = (int*)malloc( sizeof(int) * n * n);
if(rank == 0)
{
    init_matrix(n);                      // init the matrix
    

    

    for(int i = 0; i < each_row_has_block; i++) 
    {
        for(int j = 0; j < each_row_has_block; j++)        //遍历每个block
        {
            int index = 0;
            for(int m = i*block_size; m < (i+1)*block_size; m++)   //为每个block赋值
            {
                for(int w = j*block_size; w < (j+1)*block_size;w++)
                {
                    b[index] = a[m][w];
                    index++;

                }
            }

            if( i == 0 && j == 0 )      //rank==0时,先块内转置完
            {
                for(int k = 0;k<block_size;k++)
                {
                    for(int w = 0;w<block_size;w++)
                    {
                        result[k][w] = a[w][k];
                    } 
                }
            }

            else
                MPI_Send(b,block_size*block_size,MPI_INT,i*each_row_has_block+j,i*each_row_has_block+j,MPI_COMM_WORLD);
            // i*each_row_has_block+j    because  a block belongs a process
            //  buf  only one dimesion  so  b is b[n*n],
        }
    }
}
else{
    MPI_Recv(b,block_size*block_size,MPI_INT,0,rank,MPI_COMM_WORLD,&status); 

    for(int i=0;i<block_size;i++)
    {
        for(int j=0;j<block_size;j++)
        {
            int temp = b[i*block_size+j];
            b[i*block_size+j] = b[j*block_size+j];
            b[j*block_size+i] = temp;
        }
    }

    MPI_Send(b,block_size*block_size,MPI_INT,0,rank,MPI_COMM_WORLD);
}
 
 if(rank == 0)
 {
    for(int i = 0;i<each_row_has_block;i++)
    {
        for(int j = 0; j < each_row_has_block; j++)
        {
            if(i != 0 || j != 0)
            MPI_Recv(b,block_size*block_size,MPI_INT,i* each_row_has_block+j,i*each_row_has_block+j,MPI_COMM_WORLD,&status); //rank0接收各子进程传来的数据

            for(int k = 0; k < block_size; k++)        //各块进行转置
            {
                for(int l = 0; l < block_size; l++)
                {
                    result[i*block_size+k][j*block_size+l] = b[l*block_size+k];
                }
            }
        }
    }
 }

 for(int i = 0; i < n; i++)                                                    
 {
    for(int j = 0; j < n; j++)
    {
        printf("%2d ",result[i][j]);
    }
    printf("\n");
 }
double t2 = MPI_Wtime();
if(rank == 0)
printf("the time is %f seconds\n",t2 - t1);

free(a);
free(b);
free(result);

 MPI_Finalize();
 return 0;
}


在ubuntu中运行不出来。。但在windows中用VS可以跑出来(虽然也有提示错误。。)

我怎么感觉并行计算还麻烦些~…~

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值