0%

MPI小结

这段时间刚好赶上这学期的考试期,之前MPI只是稍微看了一点,在这里:并行编程 MPI初探

考完一个阶段稍微轻松些了,回来把总结补上。

Message Passing Interface

并行编程的结构大致有两种:

  1. 共享内存式系统:运算核心有多个,但是多核心通过访问一个公共的内存区域来进行协作;
  2. 分布式内存系统:运算核心有多个,每个核心有它自己的内存,多个核心之间通过通信来协作,通信可以是通过网络实现的,因此分布式系统可以做到多机并行

MPI就是一种分布式内存系统

它的全称叫做消息传递接口,就是在C、C++、Fortran的基础上又做了一套并行的函数库接口,然后运行时通过多进程之间的消息传递机制来协作完成并行任务。

MPI程序框架

首先在主函数开始时调用MPI_Init()来建立MPI进程,如果程序不需要额外的输入,则直接传入MPI_Init(NULL, NULL)

中间的代码段则是各个进程同时都会运行的部分,所以需要注意的是,MPI程序与一般的串行程序应该是完全不一样的,因为相同的代码段会被不同的进程同时运行,而需要程序员在写代码的时候就考虑到不同进程的运行情况,写出特殊的代码,进程与进程之间通过通信子来进行相互通信交换数据。

如果只是简单地将原本的串行程序放上去,那只不过是同时在多个核上跑了很多遍一模一样的代码而已,完全达不到加速的效果。

关键的MPI语句运行完毕之后,如果中间有创建过另外的通信子或者组的话,还需要单独将它们释放掉。

最后,调用MPI_Finalize()来结束MPI程序。

基本函数

1
2
3
MPI_Comm_size(
MPI_Comm comm,
int* comm_size)

返回comm通信子中的进程总数。

1
2
3
MPI_Comm_rank(
MPI_Comm comm,
int* comm_rank)

返回当前进程在comm通信子中的序号。

  • 点对点通信
1
2
3
4
5
6
7
MPI_Send(
void* msg_buf,
int msg_size,
MPI_Datatype msg_type,
int dest,
int tag,
MPI_Comm comm)

dest进程发送信息。

1
2
3
4
5
6
7
8
MPI_Recv(
void* msg_buf,
int buf_size,
MPI_Datatype buf_type,
int source,
int tag,
MPI_Comm comm,
MPI_Status* status)

source进程接收信息。

1
2
3
4
5
MPI_Probe(
int source,
int tag,
MPI_Comm comm,
MPI_Status* status)

MPI_Recv()很像,除了不能接收消息,其他都一样,主要是为了将下一条消息的各项属性保存到status里面来。

  • 集合通信
1
2
MPI_Barrier(
MPI_Comm comm)

comm通信子中的所有进程都同步到当前位置。

1
2
3
4
5
6
MPI_Bcast(
void* data_buf,
int count,
MPI_Datatype datatype,
int source,
MPI_Comm comm)

source进程向通信子中的所有其他进程发送消息。

MPI_Bcast()用的是树形结构的广播,会比单纯的从source进程开个for循环要高效的多。

然而我在单台电脑上实测的时候貌似没发现MPI_Bcast()能快多少…反而有时候还慢很多,不知道是不是我发送的东西太少了,还是电脑本身的处理速度太快了。

1
2
3
4
5
6
7
8
9
MPI_Scatter(
void* send_buf,
int send_count,
MPI_Datatype send_type,
void* recv_buf,
int recv_count,
MPI_Datatype recv_type,
int source,
MPI_Comm comm)

source进程中的send_buf均分成多份,分发给通信子中的所有进程。
需要注意的是send_countrecv_count的值是一样的,都等于每个通信子将收到的数据数量。

1
2
3
4
5
6
7
8
9
MPI_Gather(
void* send_buf,
int send_count,
MPI_Datatype send_type,
void* recv_buf,
int recv_count,
MPI_Datatype recv_type,
int dest,
MPI_Comm comm)

与上面的MPI_Scatter()非常相似,这个的作用是从多个进程中接收一定数量的数据到destrecv_buf中。
同样send_countrecv_count的值是一样的,都等于每个通信子需要发送的数据量。


这里有完整的MPI函数说明。

后话

前段时间忙着准备期末考试,原本准备好的好多个文档都没看,然后之前买的书也都没怎么看。我发现我就是擅长挖坑,然后挖了坑又填不上 o( ̄▽ ̄)d。

虽然看到现在,基本的MPI操作已经明白了,但是还是比较缺少实践。

接下来准备再看下OpenMP和CUDA,然后找点小项目来练练手吧。