MPI组通信

组通信一般实现三个功能:通信、 同步和计算。

对于组通信按通信的方向的不同,可以分为以下三种:一对多通信、多对一通信和多对多通信。

(1)广播

MPI_BCAST完成从一个标识为root的进程将一条消息广播发送到组内的所有其它的进程。

 示例代码:

int main(int argc, char* argv[])
{
    int myid, size;
    MPI_Init(&argc, &argv);
    char message[124]="my name is rank0";
    MPI_Status status;
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
 
    if (myid == 0)//0进程作为根进程
    {
        MPI_Bcast(message, 124, MPI_CHAR, 0, MPI_COMM_WORLD);
    }
    else
    {
        //各进程打印接收到的消息
        MPI_Bcast(message, 124, MPI_CHAR, 0,MPI_COMM_WORLD);
        std::cout << "rank " << myid << " received message is:" << message << std::endl;
    }
    MPI_Finalize();
return 0;
}

打印结果如下:

(2)收集

在收集调用中,每个进程将其发送缓冲区中的消息发送到根进程,根进程根据发送进程的进程标识的序号,即进程的rank值,将它们各自的消息依次存放到自已的消息缓冲区中。

int main(int argc, char* argv[])
{
    int myid, size;
    MPI_Init(&argc, &argv);
    char message[124];
    char* recv=nullptr;
    MPI_Status status;
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    sprintf_s(message, "myname is rank%d\0", myid);
    //进程0为root
    if (myid == 0)
    {
        //为Root接收缓冲区分配空间
        recv = (char*)malloc(size * 124 * sizeof(char));
    }
    //每个进程(包括根进程执行一次)执行一次发送操作
    //根进程执行一次接收操作
    MPI_Gather(message, 124, MPI_CHAR, recv, 124, MPI_CHAR, 0, MPI_COMM_WORLD);
     //接收并打印信息
    if (myid == 0)
    {
        for (int i = 0; i < size; i++)
        {
            for (int j = i * 124; j < i * 124 + 124; j++)
                std::cout << recv[j];
            std::cout << std::endl;
        }
    }
     MPI_Finalize();
    return 0;
}

执行结果如下:

 

MPI_GATHERV和MPI_GATHER的功能类似,也完成数据收集的功能。但是它可以从不同的进程接收不同数量的数据。为此,接收数据元素的个数recvcounts是一个数组,用于指明从不同的进程接收的数据元素的个数。

示例代码如下:

int main(int argc, char* argv[])
{
    int* send;           //发送数组
    int* recv=nullptr;  //接收数组
    int* buf=nullptr;   //偏移数组
    int* rcount=nullptr;//记录各个发送数组中元素的个数
    int n;               //发送数组元素个数
    int m=0;             //各进程发送的数据个数总和
    int myid, size;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    srand((unsigned)(time(NULL) + myid));
    n = rand() % 8 + myid;
    if (myid == 0)
    {
        buf = (int*)malloc(size * sizeof(int));
        rcount = (int*)malloc(size * sizeof(int));
    }
    //将各进程发送的数据个数n(包括root进程)发送给根进程
    MPI_Gather(&n, 1, MPI_INT, rcount, 1, MPI_INT, 0, MPI_COMM_WORLD);
    MPI_Barrier(MPI_COMM_WORLD);//等待各个进程全部将n发送给root
 
    //为发送数组分配数据并赋值
    send = (int*)malloc((n+1) * sizeof(int));
    for (int i = 0; i < n; i++)
    {
        send[i] = rand()%9;
    }
    if (myid == 0)
    {
        //计算接收数据个数的总和
        for (int i = 0; i < size; i++)
            m += rcount[i];
        //为接收数组分配内存
        recv = (int*)malloc(m * sizeof(int));
        //设置偏移数组
        buf[0] = 0;
        for (int i = 1; i < size; i++)
            buf[i] = buf[i - 1] + rcount[i - 1];
    }
    /*
      将各进程需发送的数据和偏移数组发送给root
    */
    MPI_Gatherv(send, n, MPI_INT, recv, rcount, buf, MPI_INT, 0, MPI_COMM_WORLD);
    //打印各进程发送的数据
    for (int i = 0; i < n; i++)
    {
        std::cout << send[i] << " ";
    }
    std::cout << std::endl;
    //打印根进程接收到的数据
    for (int i = 0; i < m; i++)
    {
        std::cout << recv[i] << " ";
    }
    MPI_Finalize();
    return 0;
}

 将进程数设置为5,打印结果如下:

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值