MPI非阻塞通信使用、性能分析与实现原理
2016-08-03 16:40
411 查看
非阻塞通信:
异步通信通常是使MPI应用程序实现高性能计算的关键,使用异步通信具有如下优势:
1)函数是非阻塞的,这使得进程在与另一个进程通信的同时继续参与计算;
2)如果应用适当,可以绕过MPI的内部buffers,极大地提高程序的通信带宽;
最常见的基本的非阻塞调用就是MPI_Isend和MPI_Irecv
MPI_Isend的使用
与同步版本的MPI_Send不同,MPI_Isend是非阻塞的。如果进程使用这一函数发送数据,函数执行完后立即返回,不用等待数据发送完毕。不过,需要注意的是,非阻塞调用在数据发送结束之前返回。所以函数MPI_Isend发送数据使用的缓冲区必须要等到数据发送结束才能够使用。例如,如下的代码是不安全的:
在上面的代码中,注意到变量i的地址传递给MPI_Isend函数作为数据发送的缓冲区地址,此处只发送一个整型数据。现在注意到在函数MPI_Isend调用之后,立刻修改变量i。这一做法实际上是不安全的,因为当我们修改变量i的值以后,数据传输没有开始或没有完成,MPI程序有可能会读取它,此时发送的数据就由123变成了234。这是一种竞争条件,很难调试出来。
避免竞争条件:
如果进程使用函数MPI_Isend和数据缓冲区buffer发送数据,并且在MPI_Isend调用后的某一执行点,需要继续使用buffer,那么就有必要等待异步发送结束后。MPI提供给我们一个函数用来检测异步发送是否完成:MPI_Wait
在上面的代码中,我们看到,进程在通信的过程中,仍然可以同时做一些其他的计算操作。非阻塞调用可以实现计算与通信的并行,这极大的提高了并行程序的效率。
接收端:
MPI_Irecv函数负责接收数据,与MPI_Isend相对应。调用以后,MPI_Irecv会立即返回,这允许进程一边接收数据一边参与与接收缓冲区无关的计算。然而,当接收进程实际使用所接收的数据的时候,必须调用MPI_Wait函数以便确保接收到的数据是有效的。
异步接收的性能:
由于异步接收和发送的特性,发送进程可以在接收进程调用MPI_Irecv之前调用MPI_Isend发送数据。在这种情况下,MPI实现会暂时将数据存储在接收进程所在主机的内部缓冲区中。但是,如果在发送进程调用MPI_Isend发送数据前,接收进程已经调用MPI_Irecv准备好接收数据,那么MPI实现就只是简单的填充程序提供的缓冲区(发送,接收缓冲区)。而不用使用MPI提供的内部缓冲区。这可以有效的去掉发生在接收进程端的内存拷贝操作,对于大数据量的处理来说,这会极大的提高性能。
因此,当发送大量数据时,最好在发送进程调用MPI_Isend之前,接收进程先调用MPI_Irecv。很多时候,这很难实现,但还是可以的,这可以帮你的程序挤出一些额外的性能。
计算与通信重叠的关键:
对于如下的数据分布,相邻结点互相之间需要对方的边界数据,为了使用通信与计算重叠,提高程序效率,可以先计算边界数据,然后使用mpi_isend异步发送,同时计算中心数据,这样可以达到将通信隐藏的目的。如果直接使用mpi_send的话会出现阻塞,双方都在等待对方接受完毕以继续,循环依赖出现死锁,需要针对死锁做进一步处理。
非阻塞通信实现原理:
根据我自己的理解其实也没有那么高深,阻塞通信出现死锁的原因并不仅仅是相邻结点同时互相发数据,也是因为阻塞通信要求确认对方已经接收完毕才会返回,此死锁主要是出现在逻辑上。非阻塞其实就是不等待对方接受,将发送数据的任务交给操作系统由系统调用(send/recv/read/write之类的)去完成,这样仅仅从逻辑上就可以避免死锁。
异步通信通常是使MPI应用程序实现高性能计算的关键,使用异步通信具有如下优势:
1)函数是非阻塞的,这使得进程在与另一个进程通信的同时继续参与计算;
2)如果应用适当,可以绕过MPI的内部buffers,极大地提高程序的通信带宽;
最常见的基本的非阻塞调用就是MPI_Isend和MPI_Irecv
MPI_Isend的使用
与同步版本的MPI_Send不同,MPI_Isend是非阻塞的。如果进程使用这一函数发送数据,函数执行完后立即返回,不用等待数据发送完毕。不过,需要注意的是,非阻塞调用在数据发送结束之前返回。所以函数MPI_Isend发送数据使用的缓冲区必须要等到数据发送结束才能够使用。例如,如下的代码是不安全的:
int i = 123; MPI_Request myRequest; MPI_Isend(&i, 1, MPI_INT, 1, MY_LITTLE_TAG, MPI_COMM_WORLD, &myRequest); i = 234;
在上面的代码中,注意到变量i的地址传递给MPI_Isend函数作为数据发送的缓冲区地址,此处只发送一个整型数据。现在注意到在函数MPI_Isend调用之后,立刻修改变量i。这一做法实际上是不安全的,因为当我们修改变量i的值以后,数据传输没有开始或没有完成,MPI程序有可能会读取它,此时发送的数据就由123变成了234。这是一种竞争条件,很难调试出来。
避免竞争条件:
如果进程使用函数MPI_Isend和数据缓冲区buffer发送数据,并且在MPI_Isend调用后的某一执行点,需要继续使用buffer,那么就有必要等待异步发送结束后。MPI提供给我们一个函数用来检测异步发送是否完成:MPI_Wait
int i = 123; MPI_Request myRequest; MPI_Isend(&i, 1, MPI_INT, 1, MY_LITTLE_TAG, MPI_COMM_WORLD, &myRequest); MPI_Status myStatus; MPI_Wait(&myRequest, &myStatus); i = 234;
在上面的代码中,我们看到,进程在通信的过程中,仍然可以同时做一些其他的计算操作。非阻塞调用可以实现计算与通信的并行,这极大的提高了并行程序的效率。
接收端:
MPI_Irecv函数负责接收数据,与MPI_Isend相对应。调用以后,MPI_Irecv会立即返回,这允许进程一边接收数据一边参与与接收缓冲区无关的计算。然而,当接收进程实际使用所接收的数据的时候,必须调用MPI_Wait函数以便确保接收到的数据是有效的。
异步接收的性能:
由于异步接收和发送的特性,发送进程可以在接收进程调用MPI_Irecv之前调用MPI_Isend发送数据。在这种情况下,MPI实现会暂时将数据存储在接收进程所在主机的内部缓冲区中。但是,如果在发送进程调用MPI_Isend发送数据前,接收进程已经调用MPI_Irecv准备好接收数据,那么MPI实现就只是简单的填充程序提供的缓冲区(发送,接收缓冲区)。而不用使用MPI提供的内部缓冲区。这可以有效的去掉发生在接收进程端的内存拷贝操作,对于大数据量的处理来说,这会极大的提高性能。
因此,当发送大量数据时,最好在发送进程调用MPI_Isend之前,接收进程先调用MPI_Irecv。很多时候,这很难实现,但还是可以的,这可以帮你的程序挤出一些额外的性能。
计算与通信重叠的关键:
对于如下的数据分布,相邻结点互相之间需要对方的边界数据,为了使用通信与计算重叠,提高程序效率,可以先计算边界数据,然后使用mpi_isend异步发送,同时计算中心数据,这样可以达到将通信隐藏的目的。如果直接使用mpi_send的话会出现阻塞,双方都在等待对方接受完毕以继续,循环依赖出现死锁,需要针对死锁做进一步处理。
非阻塞通信实现原理:
根据我自己的理解其实也没有那么高深,阻塞通信出现死锁的原因并不仅仅是相邻结点同时互相发数据,也是因为阻塞通信要求确认对方已经接收完毕才会返回,此死锁主要是出现在逻辑上。非阻塞其实就是不等待对方接受,将发送数据的任务交给操作系统由系统调用(send/recv/read/write之类的)去完成,这样仅仅从逻辑上就可以避免死锁。
相关文章推荐
- 使用NIO实现非阻塞Socket通信原理
- java并发编程学习: 阻塞队列 使用 及 实现原理
- 通信原理实践(四)——模拟通信系统性能分析
- Linux使用libnet实现ARP攻击脚本原理分析以防被攻击
- [转]PHP函数的实现原理及性能分析
- Jetty Continuation实现原理和使用场景分析
- 使用php对百度云BCS上传本地文件的实现及原理分析
- runloop实现原理初解 和 使用runloop阻塞线程
- 12-使用java5条件阻塞condition实现线程间通信-实现线程间通信方式(2)
- 百度工程师讲PHP函数的实现原理及性能分析(三)
- 百度工程师讲PHP函数的实现原理及性能分析(二)
- 百度工程师讲PHP函数的实现原理及性能分析(一)
- 百度工程师讲PHP函数的实现原理及性能分析(一)
- 百度工程师讲PHP函数的实现原理及性能分析(二)
- 百度工程师讲PHP函数的实现原理及性能分析(三)
- 一个App架构例子分析--UI层使用MVP模式;各层之间使用Otto实现通信
- 百度工程师讲PHP函数的实现原理及性能分析(一)
- 关于CCTexure2D使用opengl实现绘制的原理分析
- Jetty Continuation实现原理和使用场景分析
- php函数的实现原理及性能分析