The message passing interface
distributed address space, each processor has a local memory and has exclusive access to it.
one process is executed on one processor.
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);
blocking p2p communication
发送进程会一直等待,直到接收进程确认接收到消息为止。在这种模式下,发送进程会被阻塞(即暂停执行),直到消息被完全发送给接收进程,而接收进程也会被阻塞,直到消息被完全接收。阻塞式通信确保了消息的可靠传递,因为发送和接收的状态是明确的。
MPI_Send
MPI_Recv
messages are delivered in the order in which they have been sent
Blocking: MPI_send开始时,MPI_Recv不一定开始了 (Asynchronous)
MPI_Sendrecv
Nonblocking p2p Communication
in blocking communication: send需要等待所有数据都copy到buffer或者接收方时才可以向下执行
在非阻塞式通信中,发送进程在发送消息后可以立即继续执行后续的操作,而不必等待接收进程确认。类似地,接收进程也可以在开始接收消息后立即继续执行其他任务,而不必等待消息完全传输。
MPI_Isend
MPI_Irecv
MPI_Test
MPI_Wait
Communication Mode
在MPI(Message Passing Interface)中,通信模式定义了消息在发送和接收之间的传递方式。MPI支持多种通信模式,其中包括同步模式(Synchronous Mode)、缓冲模式(Buffered Mode)、标准模式(Standard Mode)和就绪模式(Ready Mode)。
Synchronous Mode
blocking send: MPI_Ssend()
send will not complete before the corresponding receive has been started
non-blocking send: MPI_Issend()
Control is returned after the receiver calls the corresponding MPI_Recv() or MPI_Irecv() operation.
Buffered Mode
control is returned to calling process even if the corresponding receive has not been started.
blocking send: MPI_Bsend()
allows the buffer to be reused immediately after control returns.
non-Blocking Send: MPI_Ibsend()
allows the data copying to be done concurrently with computation
在缓冲模式中,消息首先被发送到缓冲区,而不是直接发送到接收者。发送操作会立即返回,不会等待接收者的准备。接收者可以在适当的时候从缓冲区接收消息。缓冲模式提供了一定的灵活性,因为发送者不需要等待消息被接收者接收,但是接收者必须确保在处理消息之前从缓冲区接收消息,否则可能导致消息丢失。
Standard Mode
标准模式是MPI的默认通信模式。在标准模式中,消息发送后,发送操作会立即返回,不会等待接收者的准备。接收者可以在适当的时候接收消息。这种模式提供了较好的性能,但是发送者和接收者之间必须确保消息传递的正确性,以防止消息丢失。在MPI中,标准模式通常通过MPI_Send和MPI_Recv函数来实现。
Ready Mode
发送者只能发送消息给已经准备好接收消息的接收者。如果接收者没有准备好,发送者就不能发送消息。这种模式通常用于确保接收者已经准备好接收消息,以防止消息被丢失。就绪模式通常通过MPI_Recv函数的调用来实现,接收者在调用MPI_Recv之前必须确保已经准备好接收消息。
Collective Communication
这些都是blocking的
MPI communicators
在MPI(Message Passing Interface)中,通信器(communicator)是一个定义了一组进程集合以及它们之间通信关系的对象。MPI程序中的所有通信操作都是在某个通信器上进行的。通信器定义了一个进程组,这个组中的进程可以相互发送和接收消息。
通信器在MPI中的概念非常重要,因为它定义了通信的上下文,决定了哪些进程可以相互通信。MPI程序中常用的通信器有两种:MPI_COMM_WORLD 和自定义通信器。
MPI_COMM_WORLD:
MPI_COMM_WORLD 是MPI中默认的通信器。当MPI程序启动时,所有的MPI进程都自动加入到MPI_COMM_WORLD通信器中。MPI_COMM_WORLD 包含了程序中所有的MPI进程,它是一个全局的通信器。在 MPI_COMM_WORLD 中的进程可以通过它们的rank来相互通信。例如,在 MPI_COMM_WORLD 中,通过MPI_Send 和 MPI_Recv 函数可以发送和接收消息。
自定义通信器:
除了 MPI_COMM_WORLD,MPI还允许用户创建自定义的通信器。这样的通信器可以包含不同的进程子集,而不是整个程序中的所有进程。创建自定义通信器的语法如下:
MPI_Comm MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm* newcomm);
comm:父通信器,即通信器的基础。通常可以是 MPI_COMM_WORLD 或者其他自定义通信器。
group:描述了新通信器中的进程组。MPI_Group 是描述进程组的对象,可以通过 MPI_Comm_group 函数获取。
newcomm:新创建的通信器的句柄,可以在后续的通信操作中使用。
自定义通信器可以用于实现更灵活的通信拓扑结构,例如二维网格通信、树状结构通信等。通信器的使用使得MPI程序可以方便地管理进程之间的通信关系,从而更好地发挥并行计算的性能。
MPI_Comm_split 是一个MPI函数,用于将一个通信器(communicator)分割成多个子通信器,这样可以更灵活地组织进程组。分割后的子通信器可以独立地进行通信操作,而不受其他子通信器的影响。
int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm* newcomm)
comm:要分割的原始通信器。
color:用于确定子通信器的分组,具有相同颜色的进程会被放入同一个子通信器。如果两个进程的颜色相同,它们将被放在同一个子通信器中。
key:用于确定子通信器中进程的相对顺序。具有相同颜色的进程按照 key 的值进行排序。排序后的顺序决定了进程在子通信器中的 rank。
newcomm:用于存储新创建的子通信器的句柄。
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv) {
MPI_Init(&argc, &argv);
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int color = rank % 2; // 以颜色值 0 或 1 进行分组
int key = rank; // 使用进程的 rank 作为 key 进行排序
MPI_Comm newcomm;
MPI_Comm_split(MPI_COMM_WORLD, color, key, &newcomm);
int new_rank, new_size;
MPI_Comm_rank(newcomm, &new_rank);
MPI_Comm_size(newcomm, &new_size);
printf("Original rank %d, Color %d, Key %d in new communicator. New rank: %d, New size: %d\n", rank, color, key, new_rank, new_size);
MPI_Comm_free(&newcomm); // 释放子通信器
MPI_Finalize();
return 0;
}