有一个动态分配的结构:
TYPE Struct
INTEGER :: N
REAL*8 :: A
REAL*8,ALLOCATABLE :: B(:)
END TYPE Struct
它有一个动态分配的memeber:B(:)
当我尝试使用MPI_TYPE_CREATE_STRUCT为这样的Struct创建派生数据类型时,会发生不同的CPU创建不一致的派生数据类型。 这是因为struct%B(:)可能位于不同CPU上相对于第一个memeber Struct%N的不同内存位置。
然后MPI_SEND(结构,......)不会成功......
那么,如果我真的想使用MPI派生的数据类型发送这个Struct,怎么能解决这个问题?
或者禁止这种派生数据类型?
答案 0 :(得分:3)
要通过使用MPI_TYPE_CREATE_STRUCT
创建结构化数据类型,只需proceed as usual发送该结构的一个元素。根据程序的堆和堆栈相对于彼此的位置,B(1)
相对于N
的偏移可能最终成为一个巨大的正数或负数,但这不是在大多数Unix平台上都存在问题,数字应该在INTEGER(KIND=MPI_ADDRESS_KIND)
范围内。
重要提示:结构的单独实例很可能相对于B
具有不同的N
偏移量,因此MPI数据类型只能用于发送特定记录用于在构造数据类型期间获取偏移量。
当我尝试使用MPI_TYPE_CREATE_STRUCT为这样的Struct创建派生数据类型时,会发生不同的CPU创建不一致的派生数据类型。这是因为struct%B(:)可能位于不同CPU上相对于第一个memeber Struct%N的不同内存位置。
这不是问题。通信操作两侧的MPI数据类型必须只是一致的,这意味着它们应该由相同序列中的相同基本数据类型组成。 每个元素的偏移量无关。换句话说,只要发送方和接收方在MPI_TYPE_CREATE_STRUCT
调用中指定相同类型和数量的数据元素,程序就会起作用正确。
要发送多个元素,事情会变得有点复杂。有两种解决方案:
使用MPI_PACK
序列化发送方的数据,并MPI_UNPACK
在接收方进行反序列化。由于打包和解包需要额外的缓冲区空间,这会使程序的内存需求翻倍。
或
为每条记录创建单独的MPI结构数据类型,然后创建一个组合所有记录的结构数据类型。这是一个如何发送两个这样的结构的数组的示例,一个在B
中有10个元素,在一个中有20个:
TYPE(Struct) :: Structs(2)
ALLOCATE(Structs(1)%B(10))
ALLOCATE(Structs(2)%B(20))
! (1) Create a separate structure datatype for each record
DO i=1,2
CALL MPI_GET_ADDRESS(Structs(i)%N, POS_(1), IError)
CALL MPI_GET_ADDRESS(Structs(i)%A, POS_(2), IError)
CALL MPI_GET_ADDRESS(Structs(i)%B(1), POS_(3), IError)
Offsets = POS_ - POS_(1)
Types(1) = MPI_INTEGER
Types(2) = MPI_REAL8
Types(3) = MPI_REAL8
Blocks(1) = 1
Blocks(2) = 1
Blocks(3) = i * 10
CALL MPI_TYPE_CREATE_STRUCT(3, Blocks, Offsets, Types, Elem_Type(i), IError)
END DO
! (2) Create a structure of structures that describes the whole array
CALL MPI_GET_ADDRESS(Structs(1)%N, POS_(1), IError)
CALL MPI_GET_ADDRESS(Structs(2)%N, POS_(2), IError)
Offsets = POS_ - POS_(1)
Types(1) = Elem_Type(1)
Types(2) = Elem_Type(2)
Blocks(1) = 1
Blocks(2) = 1
CALL MPI_TYPE_CREATE_STRUCT(2, Blocks, Offsets, Types, TwoElem_Type, IError)
CALL MPI_TYPE_COMMIT(TwoElem_Type, IError)
! (2.1) Free the intermediate datatypes
DO i=1,2
CALL MPI_TYPE_FREE(Elem_Type(i), IError)
END DO
! (3) Send the array
CALL MPI_SEND(Structs(1)%N, 1, TwoElem_Type, ...)
请注意,虽然构建MPI数据类型是一种相对便宜的操作,但您不应使用上述过程来发送,例如1000000个结构化类型的实例。此外,MPI数据类型描述符存在于由库管理的内存中,并且不再需要的数据类型的及时释放很重要。