Parallel processing 在Fortran 90中使用MPI_Send/Recv处理多维数组块
我必须在FORTRAN 90中发送和接收(MPI)多维数组块。线路Parallel processing 在Fortran 90中使用MPI_Send/Recv处理多维数组块,parallel-processing,mpi,fortran90,Parallel Processing,Mpi,Fortran90,我必须在FORTRAN 90中发送和接收(MPI)多维数组块。线路 MPI_Send(x(2:5,6:8,1),12,MPI_Real,....) 根据Gropp、Lusk和Skjellum的《使用MPI…》一书,不应该使用。最好的方法是什么?我必须创建一个临时数组并发送它,还是使用MPI\u Type\u create\u Subarray或类似的东西?编辑:正如赫里斯托·伊利耶夫指出的那样MPI\u send总是阻塞,但可能会选择异步发送数据。发件人: 在可以使用发送缓冲区之前,MPI_发
MPI_Send(x(2:5,6:8,1),12,MPI_Real,....)
根据Gropp、Lusk和Skjellum的《使用MPI…》一书,不应该使用。最好的方法是什么?我必须创建一个临时数组并发送它,还是使用
MPI\u Type\u create\u Subarray
或类似的东西?编辑:正如赫里斯托·伊利耶夫指出的那样MPI\u send
总是阻塞,但可能会选择异步发送数据。发件人:
在可以使用发送缓冲区之前,MPI_发送不会返回
非阻塞通信(如MPI\u Send
)在涉及非连续数组时可能会对Fortran造成问题。然后,编译器为伪变量创建一个临时数组,并将其传递给子例程。一旦子例程完成,编译器就可以自由地释放该副本的内存
只要使用阻塞通信(MPI\u Send
),就可以了,因为这样子例程返回时消息就已经发送了。但是,对于非阻塞通信(MPI_Isend
),临时数组是发送缓冲区,子例程在发送之前返回
因此,MPI可能会从不再保存有效数据的内存位置发送数据
因此,要么您自己创建一个副本(以便发送缓冲区在内存中是连续的),要么您创建一个子数组(即告诉MPI您要发送的元素在内存中的地址)。还有更多的选择,比如MPI\u-Pack
,但我没有使用它们的经验
哪条路更快?那要看情况了:
- 关于MPI库的实际实现
- 论数据及其分布
- 在编译器上
- 在你的硬件上
有关详细说明和更多选项,请参阅 不在
MPI\u SEND
中使用数组节的原因是编译器必须使用一些MPI实现创建临时副本。这是因为Fortran只能正确地将数组部分传递给具有显式接口的子例程,并且在所有其他情况下,通常在调用子例程的堆栈上,必须生成临时“展平”副本。不幸的是,在F2008的TR 29113扩展之前,Fortran无法声明采用变量类型参数的子例程,MPI实现通常采用语言黑客,例如,MPI_Send
完全用C实现,并且依赖Fortran始终将数据作为指针传递
一些MPI库通过为MPI\u SEND
生成大量重载来解决此问题:
- 取一个
整数的一种
- 采用
整数的一维数组的一种
- 采用
整数
- 等等
字符
、逻辑
、双精度
等重复相同的操作。这仍然是一个难题,因为它不包括传递用户定义类型的情况。此外,它使C实现变得非常复杂,因为它现在必须理解Fortran数组描述符,这些描述符非常特定于编译器
幸运的是,时代在变化。Fortran 2008的TR 29113扩展包括两个新功能:
- 假定类型参数:
type(*)
- 假定维度参数:
维度(..)
类型(*)、维度(..)和意图(IN)::buf
,描述了一个既可以是不同类型又可以有任何维度的参数。mpi-3中新的mpi_f08
接口已经利用了这一点
非阻塞调用在Fortran中提出了更大的问题,超出了Alexander Vogt所描述的范围。原因是Fortran没有禁止编译器优化的概念(即Fortran中没有volatile
关键字)。以下代码可能无法按预期运行:
INTEGER :: data
data = 10
CALL MPI_IRECV(data, 1, MPI_INTEGER, 0, 0, MPI_COMM_WORLD, req, ierr)
! data is not used here
! ...
CALL MPI_WAIT(req, MPI_STATUS_IGNORE, ierr)
! data is used here
人们可能期望在调用MPI_WAIT
数据之后,数据将包含从秩0接收到的值,但情况可能并非如此。原因是编译器无法知道在MPI\u IRECV
返回后,data
可能会异步更改,因此将其值保留在寄存器中。这就是为什么在Fortran中,非阻塞MPI调用通常被认为是危险的
TR 29113还通过ASYNCHRONOUS
属性解决了第二个问题。如果查看mpi\u IRECV
的mpi\u f08
定义,其buf
参数声明为:
TYPE(*), DIMENSION(..), INTENT(OUT), ASYNCHRONOUS :: buf
即使buf
是一个标量参数,即没有创建临时副本,符合TR 29113的编译器也不会对缓冲区参数进行寄存器优化。这本书是否给出了使用它的理由?是不是说这不好?还是说有更好的替代方案?根据这本书(主要参考书之一),目前的MPI 2实现不一定遵循FORTRAN 90的数组语法和形式。不过,它确实显示了一些方法,但没有提到任何关于MPI\u Type\u Create\u子阵列的内容,我认为这更安全MPI_Send
可能并不总是同步的,但它总是阻塞,并且在返回后,它不再访问数据参数。您的解释仅适用于诸如MPI\u Isend
之类的调用。实际上,Fortran 2003确实有volatile
,但是异步在这里应该更好。