【问题标题】:Send variable length vector with constant header in one message在一条消息中发送带有常量标头的可变长度向量
【发布时间】:2019-05-24 23:00:29
【问题描述】:

我有 n workers、1 master(排名 0)并且需要通过 MPI 从 n workers 发送消息到 master。消息格式为可变长度向量(float *dta)和固定大小标头struct { int32_t x, int32_t y } dtaHdr。

master 只是遍历传入的结果并处理它们。能够将哪个dtaHdr与哪个dta关联起来很重要。

我知道如何:

  1. 为常量大小的dtaHdr创建MPI_Datatype并通过P2P发送MPI_Send/MPI_Recv。
  2. 通过 P2P MPI_Send/MPI_Recv 发送任意数据类型的可变长度向量(例如 MPI_Float)。

问题是我不知道如何结合这两种方法。

我知道我可以:

  • 在两个单独的消息中先发送标头,然后再发送数据。
    • 这有消息的重新排序和交错问题。我需要一种可靠、简单且可扩展的方式来关联master 上的标头及其数据。有两条消息,我看不到如何始终简单地获取主控上传入消息的标题和数据。 IE。两个workers 可以向master 发送hdr 和数据消息,它们可能会交错。 (即使在阅读 MPI 规范之后,我也不确定订购的保证是什么 TBH)。
  • 将标头和数据编码为MPI_Byte 数组,并将其作为二进制blob 发送。
    • 听起来很脏,而且违反了一些保证。

我的问题是:我如何以 MPI 惯用方式发送一个可识别的逻辑消息,其中包含一种类型的常量大小的标头和第二种类型的可变大小的向量。

【问题讨论】:

    标签: c mpi


    【解决方案1】:

    这个程序使用MPI_Pack和MPI_Unpack在同一个消息中发送两种不同的类型:

    #include <mpi.h>
    #include <stdio.h>
    
    #define ARRAY_SIZE(array) \
        (sizeof(array) / sizeof(array[0]))
    
    struct data_header {
        int32_t x;
        int32_t y;
    };
    
    MPI_Datatype dt_header;
    MPI_Datatype dt_vector;
    
    void sendmsg(void) {
        struct data_header header = { 1, 2 };
        float example[] = { 1.0, 2.0, 3.0, 4.0 };
        char buffer[4096];
        int position;
    
        MPI_Pack(&header, 1, dt_header, buffer, sizeof(buffer), &position, MPI_COMM_WORLD);
        MPI_Pack(example, 1, dt_vector, buffer, sizeof(buffer), &position, MPI_COMM_WORLD);
        MPI_Send(buffer, position, MPI_PACKED, 0, 0, MPI_COMM_WORLD);
    }
    
    void recvmsg(void) {
        struct data_header header;
        float example[4];
        char buffer[4096];
        int position = 0;
    
        MPI_Recv(buffer, sizeof(buffer), MPI_PACKED, 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        MPI_Unpack(buffer, sizeof(buffer), &position, &header, 1, dt_header, MPI_COMM_WORLD);
        MPI_Unpack(buffer, sizeof(buffer), &position, example, 1, dt_vector, MPI_COMM_WORLD);
    
        printf("x = %d, y = %d\n", header.x, header.y);
        for (int index = 0; index < ARRAY_SIZE(example); index++) {
            printf("%f ", example[index]);
        }
        printf("\n");
    }
    
    int main(void) {
        int world_size;
        int world_rank;
    
        MPI_Init(NULL, NULL);
        MPI_Comm_size(MPI_COMM_WORLD, &world_size);
        MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
    
        MPI_Type_contiguous(2, MPI_INT, &dt_header);
        MPI_Type_commit(&dt_header);
        MPI_Type_contiguous(4, MPI_FLOAT, &dt_vector);
        MPI_Type_commit(&dt_vector);
    
        if (0 == world_rank) {
            recvmsg();
        }
        else {
            sendmsg();
        }
    
        MPI_Finalize();
    
        return 0;
    }
    

    输出

    x = 1, y = 2
    1.000000 2.000000 3.000000 4.000000 
    

    这实际上只是概念验证代码。希望它能帮助您找到您正在寻找的解决方案。

    注意

    此代码不进行错误检查,不应在生产环境中使用。

    【讨论】:

    • 啊!这正是我一直在寻找的。正在考虑必须有一种方法可以将消息序列化到缓冲区。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    • 1970-01-01
    • 1970-01-01
    • 2022-12-21
    • 1970-01-01
    相关资源
    最近更新 更多