如何在 MPI_Scatter 的数组中分散多个变量

Posted

技术标签:

【中文标题】如何在 MPI_Scatter 的数组中分散多个变量【英文标题】:How to scatter multiple variables in an array for MPI_Scatter 【发布时间】:2021-04-15 09:53:58 【问题描述】:

我目前正在努力将具有 8 个整数的数组平均分配到 2 个整数 每个 4 个处理器。我使用MPI_Bcast 让每个处理器都知道总共有 8 个数组,每个数组都有 2 个整数数组,称为“my_input”。

MPI_Bcast(&totalarray,1,MPI_INT,0,MPI_COMM_WORLD);
MPI_Bcast(&my_input,2,MPI_INT,0,MPI_COMM_WORLD);

MPI_Scatter (input, 2 , MPI_INT, &my_input, 2 , MPI_INT, 0, MPI_COMM_WORLD );
//MPI_Barrier (MPI_COMM_WORLD);
printf("\n my input is %d & %d and rank is  %d \n" , my_input[0], my_input[1] , rank);

但是在分散之后,我看到打印函数无法打印“排名”,而是打印 8 个整数数组中的所有整数。我应该如何编程才能将数组的数量从 root 平均分配给其他处理器?

这是我的完整代码(仅用于测试总共 8 个整数,因此 scanf 我将输入 '8'):

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "mpi.h"

int main(int argc, char *argv[])


//initailise MPI
    MPI_Init(&argc, &argv);

    //Variable to identify processor and total number of processors
    int rank, size;
    int my_input[0];

    //initailse total array variable
    int totalarray =0;

    //initialise memory array
    int* input;

    //range of random number
    int upper = 100, lower = 0;

    //declare processor rank
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    //declare total size of processor
    MPI_Comm_size(MPI_COMM_WORLD, &size);


    //let root gather N elements from user
    if (rank == 0)
    
        printf("Enter a number from 1 to 1000: ");
        fflush(stdout);

        int number;

        //ask user to input number of elements
        scanf("%d",&number);
        printf("Your number is %d\n",number);

        //Fill the array to power of 2
        int totalarray = pow(2, ceil(log(number)/log(2)));

        input[totalarray];
        my_input[totalarray/size];

        //allocate memory for the array
        input = malloc(totalarray * sizeof(int) );

        //Add randomise number until N elements
        for(int i =0; i<=totalarray ; i++)
        
            if( i<number)
            
                input[i] = (rand() % (upper - lower + 1)) + lower; ;
            
            //padding zero to the extra elements
            else if(number <= i < totalarray)
            
                input[i] = 0;
            
        

        //confirm the input array
        printf("the input is: ");

          for(int i =0; i < totalarray ; i++)
        
          printf(  "%d  ", input[i]);
        

    
    
    MPI_Bcast(&totalarray,1,MPI_INT,0,MPI_COMM_WORLD);
    MPI_Bcast(&my_input,2,MPI_INT,0,MPI_COMM_WORLD);

    MPI_Scatter (input, 2 , MPI_INT, &my_input, 2 , MPI_INT, 0, MPI_COMM_WORLD );
    //MPI_Barrier (MPI_COMM_WORLD);
    printf("\n my input is %d & %d and rank is  %d \n" , my_input[0], my_input[1] , rank);


    MPI_Finalize();

    return 0;

【问题讨论】:

【参考方案1】:

我使用 MPI_Bcast 让每个处理器都知道有总数组 8 个,每个都有 2 个整数数组,称为“my_input”。

是的,这是有道理的。

但是在散射之后,我看到打印功能无法打印 'rank' 但来自 8 个整数数组的所有整数。我该怎么办 程序,以便将数组的数量平均分配给其他 来自根的处理器?

您的代码存在一些问题。例如,您将变量 my_inputtotalarrayinput 声明为:

int my_input[0];
...
int totalarray =0;
...
int* input;

然后在if (rank == 0) 内再次重新定义它们:

int totalarray = pow(2, ceil(log(number)/log(2)));
input[totalarray];
my_input[totalarray/size];
input = malloc(totalarray * sizeof(int) );

这是不正确的,或者您可以将两个数组都声明为int*,即:

int *my_input;
int *input;

然后在您知道每个数组中有多少元素后立即分配它们的空间。

input 数组可以在用户插入该数组的大小后立即分配:

   //ask user to input number of elements
    scanf("%d",&number);
    printf("Your number is %d\n",number);
    input = malloc(totalarray * sizeof(int));

master 进程之后的my_input 数组已将输入大小广播给其他进程:

MPI_Bcast(&totalarray, 1, MPI_INT, 0, MPI_COMM_WORLD);
int *my_input = malloc((totalarray/size) * sizeof(int));

对于变量totalarray,不要在if (rank == 0) 内再次声明。因为如果你这样做了,那么int totalarray = pow(2, ceil(log(number)/log(2))); 将是一个不同的变量,它只存在于if (rank == 0) 的范围内。

第二次MPI_Bcast 通话

MPI_Bcast(&my_input,2,MPI_INT,0,MPI_COMM_WORLD);

是除非,因为你想

平均分配数组中的总共 8 个整数到 2 个整数 4 个处理器。

并不是每个进程都拥有 master 进程的 my_input 数组的全部内容。

为此,您需要使用 MPI_Scatter。但是,而不是

  MPI_Scatter (input, 2 , MPI_INT, &my_input, 2 , MPI_INT, 0, MPI_COMM_WORLD );

不要对输入的大小进行硬编码,因为如果您想使用不同的输入大小和/或不同数量的进程进行测试,代码将不起作用,请改为执行以下操作:

  int size_per_process = totalarray/size;
  MPI_Scatter (input, size_per_process , MPI_INT, my_input, size_per_process , MPI_INT, 0, MPI_COMM_WORLD );

循环for(int i =0; i&lt;=totalarray ; i++) 实际上应该是for(int i =0; i&lt; totalarray ; i++),否则您将超出数组input 的边界。个人意见,但我认为添加随机值逻辑这样读起来更好:

    for(int i =0; i < number ; i++)
       input[i] = (rand() % (upper - lower + 1)) + lower; 
    for(int i = number; i < totalarray; i++)
       input[i] = 0;

最终代码如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "mpi.h"

int main(int argc, char *argv[])

    MPI_Init(&argc, &argv);
    int rank, size;
    int *input;
    int totalarray;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    if (rank == 0)
        printf("Enter a number from 1 to 1000: ");
        fflush(stdout);

        int number;
        scanf("%d",&number);
        printf("Your number is %d\n",number);

        totalarray = pow(2, ceil(log(number)/log(2)));

        input = malloc(totalarray * sizeof(int));
         
        int upper = 100, lower = 0;
        for(int i = 0; i < number ; i++)
           input[i] = (rand() % (upper - lower + 1)) + lower;
        for(int i = number; i < totalarray; i++)
           input[i] = 0;

        printf("the input is: ");
        for(int i =0; i < totalarray ; i++)
           printf(  "%d  ", input[i]);
    
    
    MPI_Bcast(&totalarray, 1, MPI_INT, 0, MPI_COMM_WORLD);
    int size_per_process = totalarray / size;
    int *my_input = malloc(size_per_process * sizeof(int));
    printf("SIZE PER %d\n", size_per_process);
    MPI_Scatter (input, size_per_process, MPI_INT, my_input, size_per_process, MPI_INT, 0, MPI_COMM_WORLD );
    printf("\n my input is %d & %d and rank is  %d \n" , my_input[0], my_input[1] , rank);


    MPI_Finalize();
    return 0;

也可以通过打印整个my_input 而不仅仅是前两个位置来使最后一个打印更通用。

【讨论】:

以上是关于如何在 MPI_Scatter 的数组中分散多个变量的主要内容,如果未能解决你的问题,请参考以下文章

C 中的 MPI_Scatter 结构

如何使用 MPI_Scatter 和 MPI_Gather 计算多个进程的平均值?

如何从 C 中使用 MPI_Scatter 和 MPI_Gather?

使用 MPI_Send 和 MPI_Recv 实现 MPI_Scatter 的问题

如何将一个数组拆分成多个固定长度的数组

在没有变基的情况下恢复合并