如何在 C++ 中使用 MPI 收集字符字符串并为每个进程打印它们?

Posted

技术标签:

【中文标题】如何在 C++ 中使用 MPI 收集字符字符串并为每个进程打印它们?【英文标题】:How to gather char strings and print them for each process with MPI in C++? 【发布时间】:2021-10-21 22:29:20 【问题描述】:

编辑 @GillesGouaillardet 的评论:

我正在使用 MPI 编写一个简单的 C++ 代码来进行并行处理。 我从进程 4 向 5 发送 char 消息,并为所有其他进程使用 'nothing' 初始化消息。

所以,我想收集每个进程的所有消息('nothing' 用于所有进程,但接收进程 4 发送的字符消息的第 5 个进程除外)并为每个进程打印出来,例如

Hello from process 0 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 1 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
...
Hello from process 5 among 8 of the machine jeremy-SATELLITE-P50-C
received
...

我尝试了几种类似的方法,例如:https://***.com/a/31932283/14901229,(您可以在下面的代码中看到)但它会逐字打印...

也许有人可以帮助我?提前致谢!

这是我的代码:


int rank,nbproc, taille;
    char name[80];
    
    char message[] = "preceived";
    int longueur = strlen(message); 
    int len_buffer = 200;
    char Buffer_Hello[len_buffer];
    char receive[] = "nothing";    
    
 MPI_Init(&argc, &argv);

    MPI_Comm_size(MPI_COMM_WORLD, &nbproc); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);  
    MPI_Get_processor_name(name, &taille);
    
    sprintf(Buffer_Hello,"Hello from process %d among %d of the machine %s",rank,nbproc,name);
    
    MPI_Send(Buffer_Hello,len_buffer,MPI_CHAR,0,rank+10,MPI_COMM_WORLD);

 if (rank == 4)
    
        MPI_Send(&message[1],longueur+1,MPI_CHAR,5,2,MPI_COMM_WORLD);
 // sends the message from the second element
    
 
    if (rank == 5)
       
        MPI_Recv(&receive,longueur+1,MPI_CHAR,4,2,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
    

    int mylen = strlen(receive);
    int* recvcounts = new int[nbproc*sizeof(int)]; 

    
    MPI_Gather(&mylen,1,MPI_INT,recvcounts,1,MPI_INT,0,MPI_COMM_WORLD); 
    
    int totlen = 0; 
    int* displs = new int[nbproc*sizeof(int)];


    if(rank == 0)
    
        displs[0] = 0;
        totlen += recvcounts[0] + 1; 

        for(int i=1; i < nbproc; i++)
        
            totlen += recvcounts[i]+1; 
            displs[i] = displs[i-1] + recvcounts[i-1] + 1; 
        
    


    char* totalstring = new char[totlen*sizeof(char)]; 

    if(rank == 0)
    
        for (int i=0; i<totlen; i++) 
            totalstring[i] = ' '; 
        
        totalstring[totlen] = '\0'; 
    
  
       MPI_Gatherv(&receive, mylen, MPI_CHAR,
                totalstring, recvcounts, displs, MPI_CHAR,
                0, MPI_COMM_WORLD);

  
   if(rank == 0)
   
       cout << Buffer_Hello << endl;
       
        for(int i = 1; i < nbproc; i++)
        
            MPI_Recv(Buffer_Hello,len_buffer,MPI_CHAR,i,i+10,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
            cout << Buffer_Hello << endl;
           cout << totalstring[i] << endl;
       
        
   

    MPI_Finalize(); 
    return 0;


我的输出:

Hello from process 0 among 8 of the machine jeremy-SATELLITE-P50-C
Hello from process 1 among 8 of the machine jeremy-SATELLITE-P50-C
o
Hello from process 2 among 8 of the machine jeremy-SATELLITE-P50-C
t
Hello from process 3 among 8 of the machine jeremy-SATELLITE-P50-C
h
Hello from process 4 among 8 of the machine jeremy-SATELLITE-P50-C
i
Hello from process 5 among 8 of the machine jeremy-SATELLITE-P50-C
n
Hello from process 6 among 8 of the machine jeremy-SATELLITE-P50-C
g
Hello from process 7 among 8 of the machine jeremy-SATELLITE-P50-C

【问题讨论】:

我不认为这是你的问题的根源,但你有 0 级发送给自己并且从不接收。原则上,如果 MPI_Send 实现为同步发送,它可能会死锁,但几乎可以肯定它是缓冲的,所以应该没问题。 请将您的代码缩减为minimal reproducible example,并明确说明预期结果以及它与当前结果之间的差异。 您为什么要测试 NaN,然后​​不使用该信息做任何事情? @VictorEijkhout 因为我不想打印 NaN,所以如果有一个,我什么也不打印(并且不做),但如果没有,那么它就是 else 部分。我知道这可能不是最优化的方式......我目前正在处理我的 char 收集和打印问题,我很接近,然后我可能会发布我的最终代码并可能会询问优化建议。 【参考方案1】:

我终于找到了一种方法来收集这些 char 数组并为每个进程打印出来。

首先,我从每个进程中取回所有长度不同的消息,并用它们之间的所有单词和空格组成一个大字符串。可能不是更好的方法,但如果有人有更好的想法,请告诉我!


 int mylen = strlen(receive); 
    int* recvcounts = new int[nbproc*sizeof(int)]; 

    
    MPI_Gather(&mylen,1,MPI_INT,recvcounts,1,MPI_INT,0,MPI_COMM_WORLD); 
    
    int totlen = 0; 
    int* space = new int[nbproc*sizeof(int)]; 


    if(rank == 0)
    
        displs[0] = 0; 
        totlen += recvcounts[0] + 1; 
        for(int i=1; i < nbproc; i++)
        
            totlen += recvcounts[i]+1; 
            space[i] = space[i-1] + recvcounts[i-1] + 1; 
        
    


    char* totalstring = new char[totlen*sizeof(char)]; 

    if(rank == 0)
    
        for (int i=0; i<totlen; i++) 
            totalstring[i] = ' '; 
        
        totalstring[totlen] = '\0'; 
    
  
  
       MPI_Gatherv(&receive, mylen, MPI_CHAR,
                totalstring, recvcounts, space, MPI_CHAR,
                0, MPI_COMM_WORLD);

然后我将totalstring 拆分为多个片段,并在流程 0 中以正确的顺序打印出来。


    char* piece = strtok(totalstring," "); 
  
   if(rank == 0)
   
       cout << Buffer_Hello << endl;
        cout << piece << endl;
        for(int i = 1; i < nbproc; i++)
        
            MPI_Recv(Buffer_Hello,len_buffer,MPI_CHAR,i,i+10,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
            cout << Buffer_Hello << endl;
           
            if(piece != NULL)  
            
                piece = strtok(NULL," "); 
          
                cout << piece << endl;
            
           
        
   

结果如下:

Hello from process 0 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 1 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 2 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 3 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 4 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 5 among 8 of the machine jeremy-SATELLITE-P50-C
received
Hello from process 6 among 8 of the machine jeremy-SATELLITE-P50-C
nothing
Hello from process 7 among 8 of the machine jeremy-SATELLITE-P50-C
nothing

所以,你可以看到它有效,但它可能不是最好的方法,所以如果有人有更好的想法,不要犹豫!

【讨论】:

以上是关于如何在 C++ 中使用 MPI 收集字符字符串并为每个进程打印它们?的主要内容,如果未能解决你的问题,请参考以下文章

boost mpi:字符串变量在 mpi 消息中传递是不是有最大长度?

我应该如何使用 CMake 构建 MPI C++ 程序?

如何在 C++ 中使用输入重定向添加整数

使用 MPI 在 C++ 中并行 for 循环

如何在Android Studio中随机生成一个字符串并为该字符串随机着色

使用 MPI 和 Armadillo 在 C++ 中进行并行化