【问题标题】:How to call same rank in MPI using C language?如何使用 C 语言在 MPI 中调用相同等级?
【发布时间】:2015-09-14 02:48:16
【问题描述】:

我正在尝试学习 MPI 编程并编写了以下程序。它添加一整行数组并输出总和。在等级 0(或进程 0),它将调用其所有从属等级来进行计算。我想只使用另外两个从属等级/进程来做到这一点。每当我尝试按照下面的代码所示两次调用相同的等级时,我的代码就会挂在中间并且不会执行。如果我不两次调用相同的等级,代码将正常工作

#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();
}

使用时的结果:mpirun -np 3 test

--Current Rank: 2

Sum is: 0 at rank: 2

--Current Rank: 0
* Rank 0 excecuting

--Current Rank: 1

Sum is: 524800 at rank: 1
                  //Program hangs here and wouldn't show sum of 30 

请告诉我如何才能两次调用相同的排名。例如,如果我只有两个可以调用的其他从属进程。 如果可能,请举例说明

【问题讨论】:

    标签: c mpi


    【解决方案1】:

    在 MPI 中,每个进程都执行相同的代码,并且正如您所做的那样,您主要通过检查 if/else 语句中的等级来区分不同的进程。 rank 0 的 master 进程进行 3 次发送:一次发送到 process 1,然后两次发送到 process 2。从属进程每个只进行一次接收,这意味着 rank 1 接收到它的第一个消息,而 rank 2 接收到它的第一个消息。当您在进程 0 上调用第三个MPI_Send 时,在该点之后没有也不会有任何从站等待接收消息,因为从站已经完成了它们的 else 块的执行。当主节点等待发送最终消息时,程序被阻塞。

    为了解决这个问题,您必须确保 2 级从站执行两次接收,方法是仅为该进程添加一个循环或仅对该进程重复(因此,使用if(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); 
    

    【讨论】:

      【解决方案2】:

      TL;DR: 只是说明主/从方法不受欢迎,可能会持久地格式化程序员的思维,导致投入生产时代码质量不佳


      虽然 Clarissa 是完全正确的,而且她的回答也很清楚,但我还是想补充一些一般性的评论,不是关于代码本身,而是关于并行计算理念和良好习惯。

      首先是一个简短的序言:当一个人想要并行化自己的代码时,可能有两个主要原因:使其更快和/或通过克服单台机器上的限制(如内存限制)使其能够处理更大的问题.但在所有情况下,性能都很重要,我将始终假设 MPI(或一般来说并行)程序员对性能感兴趣和关心。所以我的帖子的其余部分会假设你是。

      现在这篇文章的主要原因是:在过去的几天里,我在这里看到了一些关于 MPI 和并行化的问题,显然来自那些渴望学习 MPI(或 OpenMP)的人。这很棒!并行编程很棒,而且永远不会有足够的并行程序员。所以我很高兴(我相信许多 SO 成员也是)回答问题,帮助人们学习如何并行编程。在学习如何并行编程的背景下,你必须编写一些简单的代码,做一些简单的事情,以了解 API 的作用和工作原理。这些程序可能从远处看起来很愚蠢而且非常无效,但没关系,这就是学习的工作原理。每个人都是这样学习的。

      但是,您必须记住,您编写的这些程序只是:API 学习练习。它们不是真实的东西,它们不反映实际并行程序是什么或应该是什么的哲学。推动我在这里回答的是,我在这里和其他问题和答案中看到反复提出“主”进程和“从属”进程的状态。那是错误的,根本上是错误的!让我解释一下原因:

      正如 Clarissa 完美指出的那样,“在 MPI 中,每个进程都执行相同的代码”。这个想法是找到一种方法,使多个进程交互,以便一起解决(可能更大的)问题(希望更快)。但在这些进程中,没有一个获得任何特殊地位,它们都是平等的。他们被赋予了一个 id 以便能够解决它们,但 0 级并不比 1 级或 1025 级好……通过人为地确定进程 #0 是“主”而其他进程是它的“奴隶”,你就打破了这种对称性及其后果:

      现在排名#0 是主人,它指挥,对吧?这就是大师所做的。因此,它将获得运行代码所需的信息,将其共享分配给工作人员,指示他们进行处理。然后它将等待处理结束(可能会在中间忙起来,但更可能只是等待或戳工人,因为这是主人所做的),收集结果,进行一些重新组装并输出它。任务完成!这有什么问题?

      嗯,以下是错误的:

      1. 在主设备获取数据期间,从设备处于空闲状态。这是顺序且无效的处理...
      2. 那么数据的分布和要做的工作意味着大量的传输。这需要时间,而且由于它仅在进程 #0 和所有其他进程之间,这可能会在单个链路中的网络上造成大量拥塞。
      3. 工人在工作的时候,主人应该怎么做?工作也一样?如果是,那么当来自从站的请求到来时,它可能不容易处理,从而延迟了整个并行处理。等待这些请求?然后闲置浪费大量计算能力……最终,没有好的答案。
      4. 然后点 1 和 2 以相反的顺序重复,收集结果并输出或结果。这是大量的数据传输和顺序处理,这将严重损害全局可扩展性、有效性和性能。

      所以我希望你现在明白为什么主/从方法是错误的(通常,并非总是但经常)。我从过去几天阅读的问题和答案中看到的危险是,你可能会让你的思维被这种方法格式化,就好像它是并行的“正常”思维方式。好吧,事实并非如此!并行编程是对称的。它正在全球范围内同时在所有地方处理这个问题。您必须从一开始就考虑并行,并将您的代码视为一个全局并行实体,而不仅仅是需要指示做什么的早午餐。每个进程都是它自己的主人,在平等的基础上与它的同伴打交道。每个进程应该(尽可能地)自己获取数据(使其成为并行处理);根据处理中涉及的对等点数量及其 id 决定要做什么;必要时与同行交换信息,应该是本地(点对点通信)还是全球(集体通信);并发布自己的结果份额(再次导致并行处理)...

      好的,这对于刚开始学习并行编程的人来说有点极端,我绝不想告诉你你的学习练习应该是这样的。但请牢记目标,不要忘记 API 学习示例只是 API 学习示例,而不是实际代码的简化模型。因此,请继续尝试 MPI 调用以了解它们的作用以及它们的工作方式,但请尝试在示例中慢慢趋向于对称方法。从长远来看,这只会对您有益。

      很抱歉这个冗长且有些偏离主题的答案,祝您并行编程好运。

      【讨论】:

      • tl;dr 快速浏览一下,我并没有在您的“答案”中找到任何不同意的地方。令我困扰的是,您本可以针对您提到的任何一个最近的初学者 MPI 问题(或 SO 上的许多其他问题)发布它,这表明它不是 this 问题的好答案.我怀疑这可能是对programmers.stackexchange.com 上一个问题的一个很好的回答,但我不知道那里是否有人问过这个问题。
      • @HighPerformanceMark 你是对的,我本可以对这些初学者的任何问题做出这个答案,这更像是一个评论/建议,而不是你注意到的答案。那么为什么这个问题而不是其他问题呢?也许只是在这里准备好并在将来需要时参考它......这是否看起来足够符合 SO 的使用政策?
      • 我不确定我是否知道 SO 的使用政策是什么——除了让社区来决定。这是有用的信息和建议,并且至少与问题相关,这两者都使其在此处大约 50% 的答案之上。我当然不会投反对票,事实上,该死的,我要投赞成票……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-04
      • 2019-01-27
      • 2020-08-16
      • 1970-01-01
      • 1970-01-01
      • 2016-09-18
      • 1970-01-01
      相关资源
      最近更新 更多