首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用MPI_Pack时收到的垃圾值,并与MPI_send和Recieve一起解压缩

使用MPI_Pack时收到的垃圾值,并与MPI_send和Recieve一起解压缩
EN

Stack Overflow用户
提问于 2021-04-06 17:08:59
回答 1查看 250关注 0票数 3

我试图将矩阵的一部分从一个过程发送到另一个过程。这是给定的矩阵

它有10行8列。我试图发送一半的列(4到7)注->矩阵从进程0索引到进程1,借助MPI_Pack()。为此,我将使用以下代码

代码语言:javascript
复制
 double snd_buf[4][r];   //r is the number of rows
    double recv_buf[4][r];
    double buf[4][r];

   MPI_Request request[c];    //c is the number of columns
    MPI_Request request1[c];
    MPI_Status status[c];

//packing and sending the data
        if(myrank==0)
            {
                //we will send the half of the matrix to process 2
                for(int j=4;j<c;j++)
                {
                    position=0; //reassigning position after each and every send
                    
                    for(int i=0;i<r;i++)
                    {
                        MPI_Pack(&mat[i][j], 1 , MPI_DOUBLE,snd_buf[j-4],80,&position,MPI_COMM_WORLD);
                    }
                }
                
                
                //sending all the buffers
                for(int j=4;j<c;j++)
                {
                    MPI_Send (snd_buf[j-4], 10 , MPI_PACKED, 1 /*dest*/ , j /*tag*/ , MPI_COMM_WORLD);
                }
                
                
                
            } 

为了接收,我使用了以下代码。

代码语言:javascript
复制
if(myrank==1)
        {
        
             for(j=4;j<c;j++)
             {      
                 MPI_Recv(recv_buf[j-4], 10, MPI_PACKED, 0 /*src*/ , j /*tag*/, MPI_COMM_WORLD,&status[j]);
                 
             }
            
            for(int j=4; j<c;j++)
            {
                position=0;
                 for(int i=0;i<r;i++)
                 {
                    MPI_Unpack(recv_buf[j-4],80,&position,&buf[j-4][i], 1/*outcount*/, MPI_DOUBLE, MPI_COMM_WORLD);
                 }
            }
}

但是,当我打印recv_buf的值时,我只得到每一行的第一个元素,在某些情况下,后面跟着0,在某些情况下,还有一些垃圾值。下面给出了recv_buf的内容。

例-1:

例2:

我也检查过我的snd_buf[],但是它把所有的值都包装得很好。

我不会在recv_buf中得到这些0,有时甚至是垃圾值。请帮帮忙。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-06 19:58:54

第一

代码语言:javascript
复制
double snd_buf[4][r];   //r is the number of rows
double recv_buf[4][r];
double buf[4][r];

我想你的意思是:

代码语言:javascript
复制
double snd_buf[r][4];   //r is the number of rows
double recv_buf[r][4];
double buf[r][4];

来源可以读到:

MPI_Pack -将给定数据类型的数据打包到连续内存中。

你在滥用包装/拆包功能。与其打包要发送的每个元素,您只需要用要发送的列打包行。由于行是连续地在内存中分配的,所以您可以一次打包它们,不需要分别打包每一列。此外,您正在对发送执行多个调用:

代码语言:javascript
复制
   for(int j=0;j<c;j++){
      MPI_Send (snd_buf[j-4], 10 , MPI_PACKED, 1 /*dest*/ , j /*tag*/ , MPI_COMM_WORLD);
  }

打包的目的是将所有东西打包到一个缓冲区中,并一次性发送/恢复它。如果要执行多个MPI_Send,那么打包没有什么好处,最好直接发送/接收列,而不必打包任何内容,如下所示:

代码语言:javascript
复制
if(myrank==0){
   for(int i=0;i<r;i++) // Send 4 columns of each row
       MPI_Send (&mat[i], 4, MPI_DOUBLE, 1, i, MPI_COMM_WORLD);
       
 }
 ...
 if(myrank==1){
    for(int i=0;i<r;i++){ // receive 4 columns of each row
      MPI_Recv(&mat[i], 4, MPI_DOUBLE, 0, i ...);
  }

除其他外,这些都是您需要在逻辑中修复的基本错误,以使其正常工作。

尽管如此,通过发送一半的行而不是一半的列来解决这个问题要容易得多,效率也高得多。

您可以首先分配一个连续二维阵列 (或者简单地将矩阵表示为一个数组),只需用一个调用发送/重新分配一半的行。

下面是一个演示该方法的玩具示例(它只适用于两个过程,而且还没有生产准备):

代码语言:javascript
复制
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"

#define ROWS 10
#define COLS 8

int main( int argc, char *argv[])
{
     MPI_Status status;
     MPI_Init(&argc, &argv);    
     int myrank, size; //size will take care of number of processes 
     MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
     MPI_Comm_size(MPI_COMM_WORLD, &size);
         
     if(myrank == 0){
        int (*arr)[COLS] = malloc(sizeof *arr * ROWS);
        // Just faking some data
        for(int i = 0; i < ROWS; i++)
           for(int j = 0; j < COLS; j++)
              arr[i][j] = i;
            
        MPI_Send(&arr[ROWS/2], ROWS/2 * COLS, MPI_INT, 1, 0, MPI_COMM_WORLD);
    }else{    
        int (*arr)[COLS] = malloc(sizeof *arr * ROWS/2);
        MPI_Recv(arr, ROWS/2 * COLS, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
        for(int i = 0; i < ROWS/2; i++){
           for(int j = 0; j < COLS; j++)
               printf("%d ",arr[i][j]);
           printf("\n");
        }
    }
   MPI_Finalize();
   return 0;
}

输入:

代码语言:javascript
复制
0 0 0 0 0 0 0 0 
1 1 1 1 1 1 1 1 
2 2 2 2 2 2 2 2 
3 3 3 3 3 3 3 3 
4 4 4 4 4 4 4 4 
5 5 5 5 5 5 5 5 
6 6 6 6 6 6 6 6 
7 7 7 7 7 7 7 7 
8 8 8 8 8 8 8 8 
9 9 9 9 9 9 9 9 

输出:

代码语言:javascript
复制
5 5 5 5 5 5 5 5 
6 6 6 6 6 6 6 6 
7 7 7 7 7 7 7 7 
8 8 8 8 8 8 8 8 
9 9 9 9 9 9 9 9 

要将这种方法扩展到多个进程,您应该将点对点通信例程(即MPI_SendMPI_Recv)替换为集体通信例程斯卡特捷夫

将缓冲区分散到通信器中的所有进程。

GatherV

从组中的所有进程聚集到指定的位置。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66973279

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档