标签问题是由于如何在不同进程上计算(或不计算)标签而导致的。您正在将所有进程的标签值初始化为
int tag = 1;
之后,对于进程等级 0,您将标记设置为
tag = a+b;
这是第一次设置,将设置tag
为 0 因为两者a
and b
从零开始。但是,对于等级高于 0 的进程,标记永远不会更改。他们将继续将标签设置为 1。
该标签唯一标识正在发送的消息MPI_Isend
and MPI_Irecv
,这意味着发送及其相应的接收必须具有相同的标记才能使数据传输成功。由于大多数接收进程之间的标签不匹配,因此传输大多不成功。这会导致排名高于 0 的进程最终在调用时永远阻塞(等待)MPI_Wait
.
为了解决这个问题,您必须确保更改排名高于零的进程的标签。然而,在我们做到这一点之前,还有一些其他问题值得讨论。
按照您现在为排名 0 进程设置标签的方式,tag
只能有 0 到 4 的值(假设有 3 个进程)。这是因为a
限制在 0 到 3 的范围内,并且b
只能有值 0 或 1。这些值的最大可能总和是 4。这意味着当您使用arr[tag][0]
,您将错过很多数据,并且您将多次重新发送相同的行。我建议更改发送每个子数组的方式(您当前正在使用tag
),这样您就只有一个 for 循环来确定要发送哪个子数组,而不是两个嵌入式循环。然后,您可以计算将数组发送到的过程:
dest = subarray_index%(world_size - 1) + 1;
这将在等级大于零的进程之间交替目的地。您可以将标签保留为subarray_index
。在接收端,您需要计算每个进程、每个接收的标签。
最后,我看到您在发送数据后正在初始化数组。你想提前这样做。
结合所有这些方面,我们得到
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
MPI_Init(&argc, &argv);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
int tag = 1;
int arr[8][10];
MPI_Request request;
MPI_Status status;
int source = 0;
int dest;
printf ("\n--Current Rank: %d\n", world_rank);
if (world_rank == 0)
{
int i = 0;
int a, b, x, y;
printf("* Rank 0 excecuting\n");
//I've moved the array generation to before the sends.
for(x=0; x<8; x++)//Generating the whole 8 by 10 2D array
{
i++;
for ( y = 0; y < 10; y++ )
{
arr[x][y] = i;
}
}
//I added a subarray_index as mentioned above.
int subarray_index;
for(subarray_index=0; subarray_index < 8; subarray_index++)
{
dest = subarray_index%(world_size - 1) + 1;
tag = subarray_index;
MPI_Isend(&arr[subarray_index][0], 10, MPI_INT, dest, tag, MPI_COMM_WORLD, &request);
}
}
else
{
int a, b;
for(b=0; b<8/(world_size-1); b++)
{
int sum = 0;
int i;
//We have to do extra calculations here. These match tag, dest, and subarray.
int my_offset = world_rank-1;
tag = b*(world_size-1) + my_offset;
int subarray = b;
MPI_Irecv(&arr[subarray][0], 10, MPI_INT, source, tag, MPI_COMM_WORLD, &request);
MPI_Wait (&request, &status);
for(i = 0; i<10; i++)
{
sum = arr[subarray][i]+sum;
}
printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, tag);
}
}
MPI_Finalize();
}
在这个版本中,有一件事似乎还没有完成,需要你考虑:如果你的进程数量发生变化,会发生什么?例如,如果您有 4 个进程而不是 3 个,那么循环可能会遇到一些问题
for(b=0; b<8/(world_size-1); b++)
因为每个进程都会执行相同的次数,但发送的数据量并不能完全分配给 3 个工作进程(非零级进程)。
但是,如果您不关心这一点,那么您就不需要处理此类情况。