c-我在学习mpi-send和recv函数的例子时有一个问题



下面的代码显示了研究发送和响应函数时的乒乓球示例。但我不明白从伙伴级别。

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
const int PING_PONG_LIMIT = 10;
// Initialize the MPI environment
MPI_Init(NULL, NULL);
// Find out rank, size
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);

// We are assuming 2 processes for this task
if (world_size != 2) {
fprintf(stderr, "World size must be two for %sn", argv[0]);
MPI_Abort(MPI_COMM_WORLD, 1);
}
int ping_pong_count = 0;
int partner_rank = (world_rank + 1) % 2;
while (ping_pong_count < PING_PONG_LIMIT) {
if (world_rank == ping_pong_count % 2) {
// Increment the ping pong count before you send it
ping_pong_count++;
MPI_Send(&ping_pong_count, 1, MPI_INT, partner_rank, 0, MPI_COMM_WORLD);
printf("%d sent and incremented ping_pong_count %d to %dn", world_rank, ping_pong_count, partner_rank);
} else {
MPI_Recv(&ping_pong_count, 1, MPI_INT, partner_rank, 0, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
printf("%d received ping_pong_count %d from %dn", 
world_rank, ping_pong_count, partner_rank);}
}
MPI_Finalize();
}

Q1.很明显,上面的MPI_Comm_rank将其定义为world_rank,但我不明白下面的partner_rank是什么意思。这两个级别之间有什么区别?

Q2.当我不理解if (world_rank == ping_pong_count % 2)难道我们就不能写";秩==0";以及";秩==1";?你为什么在里面放一个算术运算符?

非常感谢你的评论。

这种看似不必要的算术和引入额外秩变量的原因是代码对称性。也就是说,由于最常见的MPI程序类型是作为同一程序多个副本运行的程序,因此对称代码意味着没有条件语句将秩与特定常量进行比较的代码。为什么这很重要?因为它使代码更加灵活和易于理解。

比较以下两个等价的规范,说明两级MPI乒乓程序的样子:

规格1

  • rank 0向rank 1发送消息
  • 等级1然后将消息发送回等级0
  • 该过程重复N次

该规范在类C伪代码中的实现可以是:

loop N times {
if (rank == 0) {
MPI_Send to 1
MPI_Recv from 1
}
else if (rank == 1) {
MPI_Recv from 0
MPI_Send to 0
}
}

规格2

  • 每个等级从另一个等级接收
  • 然后每个列发送到另一个列
  • 该过程重复N-1次
  • 此外,秩0通过发送到另一个秩来启动进程,并通过接收来自另一个列的最后一条消息来结束进程

伪代码中的一种可能实现:

other_rank = 1 - rank
if (rank == 0) {
MPI_Send to other_rank
}
loop N-1 times {
MPI_Recv from other_rank
MPI_Send to other_rank
}
if (rank == 0) {
MPI_Recv from other_rank
}

第二个规范(及其实现(乍一看可能更复杂,但事实并非如此。它的优点是它是局部的-它没有给出特定级别必须做什么的全局处方。相反,它给出了系统中任何级别都要做什么的处方,只是在过程的开始和结束时打破了对称性,因为必须有东西启动链。

如果我们想扩展系统,并且在一个环中传递消息的不是两个,而是三个等级,该怎么办。我们希望秩0将消息传递给秩1,然后秩1将消息传递到秩2,秩2又将消息传递回秩0。扩展规范1导致:

  • 秩0发送到秩1
  • 秩0从秩2接收
  • 秩1从秩0接收
  • 秩1发送到秩2
  • 秩2从秩1接收
  • 秩2发送到秩0

在伪代码中:

loop N times {
if (rank == 0) {
MPI_Send to 1
MPI_Recv from 2
}
else if (rank == 1) {
MPI_Recv from 0
MPI_Send to 2
}
else if (rank == 2) {
MPI_Recv from 1
MPI_Send to 0
}
}

试着将其扩展到四个等级,然后再扩展到五个等级。

另一方面,规范2自然地扩展到三、四。。。实际上,适用于任何级别:

  • 每个等级从上一个等级接收
  • 每个列发送到下一个列
  • 秩0通过发送第一条消息启动进程,通过接收最后一条消息结束进程

在伪代码中:

prev_rank = (rank - 1 + #ranks) % #ranks
next_rank = (rank + 1) % #ranks
if (rank == 0) {
MPI_Send to next_rank
}
loop N-1 times {
MPI_Recv from prev_rank
MPI_Send to next_rank
}
if (rank == 0) {
MPI_Recv from prev_rank
}

值得注意的是,规范2不过是#ranks等于2的该通用规范的特定情况。在这种情况下,prev_ranknext_rank都等于(rank + 1) % 2,即是同一个秩。此外,当秩采用01的值时,(rank + 1) % 21 - rank是相同的。

我希望你现在看到的动机不是将特定的操作硬编码到特定的等级,而是使用本地算术来确定该做什么。在你的情况下,每个偶数ping消息值都会增加等级0,每个奇数ping消息值会增加等级1,但如果你将其扩展到一个等级环呢?if (rank == ping_value % #ranks) ping_value++;做了正确的事情,可以与任何级别一起工作。

相关内容

  • 没有找到相关文章

最新更新