如何使用C语言在MPI中调用相同的秩?
我正在努力学习MPI编程,并编写了以下程序。它添加整个数组行并输出总和。在秩0(或进程0)处,它将调用其所有从属秩来进行计算。我只想使用另外两个从属列组/进程来实现这一点。每当我尝试调用相同的排名两次,如代码波纹管中所示,我的代码将只是挂在中间,不会执行。如果我不调用同一个秩两次,代码将正常工作如何使用C语言在MPI中调用相同的秩?,c,mpi,C,Mpi,我正在努力学习MPI编程,并编写了以下程序。它添加整个数组行并输出总和。在秩0(或进程0)处,它将调用其所有从属秩来进行计算。我只想使用另外两个从属列组/进程来实现这一点。每当我尝试调用相同的排名两次,如代码波纹管中所示,我的代码将只是挂在中间,不会执行。如果我不调用同一个秩两次,代码将正常工作 #include "mpi.h" #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]
#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 tag2 = 1;
int arr[30] = {0};
MPI_Request request;
MPI_Status status;
printf ("\n--Current Rank: %d\n", world_rank);
int index;
int source = 0;
int dest;
if (world_rank == 0)
{
int i;
printf("* Rank 0 excecuting\n");
index = 0;
dest = 1;
for ( i = 0; i < 30; i++ )
{
arr[ i ] = i + 1;
}
MPI_Send(&arr[0], 30, MPI_INT, dest, tag2, MPI_COMM_WORLD);
index = 0;
dest = 2;
for ( i = 0; i < 30; i++ )
{
arr[ i ] = 0;
}
MPI_Send(&arr[0], 30, MPI_INT, dest, tag2, MPI_COMM_WORLD);
index = 0;
dest = 2; //Problem happens here when I try to call the same destination(or rank 2) twice
//If I change this dest value to 3 and run using: mpirun -np 4 test, this code will work correctly
for ( i = 0; i < 30; i++ )
{
arr[ i ] = 1;
}
MPI_Send(&arr[0], 30, MPI_INT, dest, tag2, MPI_COMM_WORLD);
}
else
{
int sum = 0;
int i;
MPI_Irecv(&arr[0], 30, MPI_INT, source, tag2, MPI_COMM_WORLD, &request);
MPI_Wait (&request, &status);
for(i = 0; i<30; i++)
{
sum = arr[i]+sum;
}
printf("\nSum is: %d at rank: %d\n", sum, world_rank);
}
MPI_Finalize();
}
请让我知道我怎样才能叫同一个等级两次。例如,如果我只能调用另外两个从进程。
如果可能的话,请举例说明在MPI中,每个进程执行相同的代码,并且在您执行时,主要通过检查if/else语句中的秩来区分不同的进程。秩为0的主进程正在执行3次发送:一次发送到进程1,然后两次发送到进程2。从属进程每个只执行一次接收,这意味着秩1接收其第一条消息,秩2接收其第一条消息。当您在进程0上调用第三个
MPI_Send
时,由于从机已完成执行其else块,因此在该点之后不会有任何从机等待接收消息。当主机等待发送最终消息时,程序被阻止
为了解决这个问题,您必须确保秩2的从机执行两次接收,或者只为该进程添加一个循环,或者只为该进程重复一次(因此,如果(world_rank==2)检查)代码块
sum = 0; //resetting sum
MPI_Irecv(&arr[0], 1024, MPI_INT, source, tag2, MPI_COMM_WORLD, &request);
MPI_Wait (&request, &status);
for(i = 0; i<1024; i++)
{
sum = arr[i]+sum;
}
printf("\nSum is: %d at rank: %d\n", sum, world_rank);
sum=0//重置总和
MPI_Irecv(&arr[0],1024,MPI_INT,source,tag2,MPI_COMM_WORLD,&request);
MPI_等待(&请求,&状态);
对于(i=0;i来说,这只是一句话,主/从方法不受欢迎,可能会长期影响程序员的思维,导致在投入生产时产生糟糕的代码
尽管Clarissa是完全正确的,她的答案也非常清楚,但我想补充几点一般性的意见,不是关于代码本身,而是关于并行计算哲学和良好习惯
首先是一个简短的前言:当一个人想要并行化自己的代码时,可能有两个主要原因:提高速度和/或允许它通过克服单机上的限制(如内存限制)来处理更大的问题。但在所有情况下,性能都很重要,我始终认为MPI(或者一般来说是并行的)程序员对性能感兴趣,所以我的文章的其余部分会假设你是
现在写这篇文章的主要原因是:在过去的几天里,我在这里看到了一些关于MPI和并行化的问题,显然是来自渴望学习MPI(或OpenMP)的人们。这太棒了!并行编程太棒了,而且永远不会有足够的并行程序员。所以我很高兴(我相信很多会员也是)回答帮助人们学习如何并行编程的问题。在学习如何并行编程的背景下,你必须编写一些简单的代码,做一些简单的事情,以便理解API的功能和工作原理。从远处看,这些程序可能看起来很愚蠢,效率很低,但没关系,就是这样学习是有效的。每个人都是这样学习的
然而,你必须记住,你写的这些程序只是:API学习练习。它们不是真实的东西,它们没有反映出实际并行程序是什么或应该是什么的哲学。我在这里的答案是,我在这里看到的以及在其他问题和答案中反复提出的f“主”过程和“从”过程。这是错误的,根本上是错误的!让我解释一下原因:
正如Clarissa完美指出的,“在MPI中,每个进程执行相同的代码”。其想法是找到一种方法,使多个进程相互作用,共同解决一个(可能更大的)问题(希望更快).但在这些进程中,没有一个进程获得任何特殊的地位,它们都是平等的。它们被赋予一个id来处理它们,但秩0并不比秩1或秩1025好……通过人为地确定进程#0是“主”而其他进程是其“从”,你打破了这种对称性,并产生了以下后果:
现在秩#0是主控,它命令,对吗?主控就是这样做的。因此,它将获得运行代码所需的信息,将其共享分配给工作人员,并指示他们进行处理。然后它将等待处理结束(可能在这两者之间忙得不可开交,但更可能只是等待或戳工人,因为这是大师的工作),收集结果,重新组装并输出。工作完成了!这有什么不对
好吧,以下是错误的:
在主机获取数据的过程中,从机处于空闲状态。这是一种顺序的、无效的处理
然后,数据的分布和要做的工作意味着大量的传输。这需要时间,而且因为它仅在进程0和所有其他进程之间,这可能会在一条链路中造成网络上的大量拥塞
当工人做他们的工作时,主人应该做什么?也工作吗?如果是的话,那么当奴隶来的时候,它可能无法处理奴隶的请求,从而延迟了整个并行处理。等待这些请求?然后它会因闲置而浪费大量计算能力……最终,没有好的答案
然后以相反的顺序重复第1点和第2点,收集结果并输出结果。这是大量的数据传输和顺序处理,这将严重损害全局可扩展性、有效性和性能
所以我希望你们现在明白为什么主/从方法是(通常,不总是)
sum = 0; //resetting sum
MPI_Irecv(&arr[0], 1024, MPI_INT, source, tag2, MPI_COMM_WORLD, &request);
MPI_Wait (&request, &status);
for(i = 0; i<1024; i++)
{
sum = arr[i]+sum;
}
printf("\nSum is: %d at rank: %d\n", sum, world_rank);