【问题标题】:OpenMPI multiple MPI_Send and MPI_recv not workingOpenMPI 多个 MPI_Send 和 MPI_recv 不起作用
【发布时间】:2012-11-16 03:30:53
【问题描述】:

当我尝试在程序中调用多个 MPI_Send 或 MPI_Recv 时,可执行文件在节点和根目录中被挂起。即,当它试图执行第二个 MPI_Send 或 MPI_Recv 时,通信被阻塞。同时,二进制文件在机器中以 100% 的速度运行。

当我尝试使用 OpenMPI 1.6.3 64 位在 windows 7 64 位中运行此代码时,它运行成功。但是相同的代码在 Linux 中不起作用,即 CentOS 6.3 x86_64 和 OpenMPI 1.6.3 -64 位。我做了什么问题。

下面贴出代码

#include <mpi.h>

int main(int argc, char** argv) {
MPI::Init();
int rank = MPI::COMM_WORLD.Get_rank();
int size = MPI::COMM_WORLD.Get_size();
char name[256] = { };
int len = 0;
MPI::Get_processor_name(name, len);

printf("Hi I'm %s:%d\n", name, rank);

if (rank == 0) 
{
    while (size >= 1) 
    {
        int val, stat = 1;
        MPI::Status status;
        MPI::COMM_WORLD.Recv(&val, 1, MPI::INT, 1, 0, status);
        int source = status.Get_source();
        printf("%s:%d received %d from %d\n", name, rank, val, source);

        MPI::COMM_WORLD.Send(&stat, 1, MPI::INT, 1, 2);
        printf("%s:%d sent status %d\n", name, rank, stat);

        size--;
    }
} else 
{
    int val = rank + 10;
    int stat = 0;
    printf("%s:%d sending %d...\n", name, rank, val);
    MPI::COMM_WORLD.Send(&val, 1, MPI::INT, 0, 0);
    printf("%s:%d sent %d\n", name, rank, val);

    MPI::Status status;
    MPI::COMM_WORLD.Recv(&stat, 1, MPI::INT, 0, 2, status);
    int source = status.Get_source();
    printf("%s:%d received status %d from %d\n", name, rank, stat, source);
}

size = MPI::COMM_WORLD.Get_size();
if (rank == 0) 
{
    while (size >= 1) 
    {
        int val, stat = 1;
        MPI::Status status;

        MPI::COMM_WORLD.Recv(&val, 1, MPI::INT, 1, 1, status);
        int source = status.Get_source();
        printf("%s:0 received %d from %d\n", name, val, source);

        size--;
    }

    printf("all workers checked in!\n");
} 
else
{
    int val = rank + 10 + 5;
    printf("%s:%d sending %d...\n", name, rank, val);
    MPI::COMM_WORLD.Send(&val, 1, MPI::INT, 0, 1);
    printf("%s:%d sent %d\n", name, rank, val);
}
MPI::Finalize();

return 0;

}

嗨,Hristo,我已经按照你说的更改了源代码,代码再次发布

    #include <mpi.h>
#include <stdio.h>

int main(int argc, char** argv) 
{
    int iNumProcess = 0, iRank = 0, iNameLen = 0, n;
    char szNodeName[MPI_MAX_PROCESSOR_NAME] = {};
    MPI_Status stMPIStatus;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &iNumProcess);
    MPI_Comm_rank(MPI_COMM_WORLD, &iRank);
    MPI_Get_processor_name(szNodeName, &iNameLen);

    printf("Hi I'm %s:%d\n", szNodeName, iRank);

    if (iRank == 0) 
    {
        int iNode = 1;
        while (iNumProcess > 1) 
        {
            int iVal = 0, iStat = 1;
            MPI_Recv(&iVal, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &stMPIStatus);
            printf("%s:%d received %d\n", szNodeName, iRank, iVal);

            MPI_Send(&iStat, 1, MPI_INT, iNode, 1, MPI_COMM_WORLD);
            printf("%s:%d sent Status %d\n", szNodeName, iRank, iStat);

            MPI_Recv(&iVal, 1, MPI_INT, MPI_ANY_SOURCE, 2, MPI_COMM_WORLD, &stMPIStatus);
            printf("%s:%d received %d\n", szNodeName, iRank, iVal);

            iNumProcess--;
            iNode++;
        }

        printf("all workers checked in!\n");
    }
    else 
    {
        int iVal = iRank + 10;
        int iStat = 0;
        printf("%s:%d sending %d...\n", szNodeName, iRank, iVal);
        MPI_Send(&iVal, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
        printf("%s:%d sent %d\n", szNodeName, iRank, iVal);

        MPI_Recv(&iStat, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &stMPIStatus);
        printf("%s:%d received status %d\n", szNodeName, iRank, iVal);

        iVal = 20;
        printf("%s:%d sending %d...\n", szNodeName, iRank, iVal);
        MPI_Send(&iVal, 1, MPI_INT, 0, 2, MPI_COMM_WORLD);
        printf("%s:%d sent %d\n", szNodeName, iRank, iVal);

    }

    MPI_Finalize();

    return 0;
}

我得到如下输出。即,在发送发送/接收之后,root 无限等待并且节点正在以 100% 的 CPU 利用率运行。它的输出如下

Hi I'm N1433:1
N1433:1 sending 11...
Hi I'm N1425:0
N1425:0 received 11
N1425:0 sent Status 1
N1433:1 sent 11
N1433:1 received status 11
N1433:1 sending 20...

这里 N1433 和 N1425 是机器名称。请帮忙

【问题讨论】:

    标签: linux 64-bit centos openmpi


    【解决方案1】:

    主人的代码是错误的。它总是发送和等待来自同一等级的消息 - 等级1。因此,程序只有在以mpiexec -np 2 ... 运行时才能正常运行。您可能想要做的是使用MPI_ANY_SOURCE 作为源排名,然后使用该源排名作为发送操作中的目标。您也不应该使用while (size &gt;= 1),因为等级0 不会与自己对话,并且通信次数预计会比size 少一。

    if (rank == 0) 
    {
        while (size > 1)
        //     ^^^^^^^^
        {
            int val, stat = 1;
            MPI::Status status;
            MPI::COMM_WORLD.Recv(&val, 1, MPI::INT, MPI_ANY_SOURCE, 0, status);
            // Use wildcard source here ------------^^^^^^^^^^^^^^
            int source = status.Get_source();
            printf("%s:%d received %d from %d\n", name, rank, val, source);
    
            MPI::COMM_WORLD.Send(&stat, 1, MPI::INT, source, 2);
            // Send back to the same process --------^^^^^^
            printf("%s:%d sent status %d\n", name, rank, stat);
    
            size--;
        }
    } else
    

    在worker中做这样的事情是没有意义的:

    MPI::Status status;
    MPI::COMM_WORLD.Recv(&stat, 1, MPI::INT, 0, 2, status);
    // Source rank is fixed here ------------^
    int source = status.Get_source();
    printf("%s:%d received status %d from %d\n", name, rank, stat, source);
    

    您已经将等级0 指定为接收操作中的源,因此它只能接收来自等级0 的消息。 status.Get_source() 不可能返回除0 以外的任何值,除非发生了一些通信错误,在这种情况下,MPI::COMM_WORLD.Recv() 会抛出异常。

    代码中的第二个循环也是如此。

    顺便说一句,您使用的是以前的官方标准 C++ 绑定。它们在 MPI-2.2 中被弃用,最新版本的标准 (MPI-3.0) 完全删除了它们,因为 MPI 论坛不再支持它们。您应该改用 C 绑定或依赖 3-rd 方 C++ 接口,例如 Boost.MPI

    【讨论】:

    • 嗨 Hristo,我已经更改了来源和下面的帖子。
    【解决方案2】:

    在安装 MPICH2 而不是 OpenMPI 后,它成功运行。我认为在我的集群机器中使用 OpenMPI 1.6.3 存在一些问题。

    【讨论】:

      猜你喜欢
      • 2011-11-11
      • 2015-05-14
      • 2014-04-17
      • 2011-01-24
      • 1970-01-01
      • 2017-10-25
      • 2016-04-22
      • 2021-08-03
      • 1970-01-01
      相关资源
      最近更新 更多