3.3数据类型匹配和数据转换 | ![]() ![]() |
3.3.1 类型匹配规则
我们能认为消息传送由下列三个阶段组成。
1. 数据从消息缓存中取出并安装成一个消息。
2. 一个消息从发送者传送到接收者。
3. 从这个消息中取出数据并拆开送入接收缓存。
在这三个阶段,没有看到类型匹配:在发送者缓存中的每个变量类型必须匹配该发送操作为输如指定的类型;由发送操作指定的类型必须匹配由接收操作指定的类型;在接收缓存中的每个变量的类型必须匹配由接收操作为指定的类型。不能观察到这三个规则的程序是错误的。
为了更精确地定义,我们必须处理两个问题:宿主语言的类型和通信操作指定的类型匹配;发送者和接收者的类型匹配。
如果发送和接收操作使用同一类型名字,那么这个发送和接收操作类型匹配(第二阶段)。即,MPI_INTEGER匹配MPI_INTEGER, MPI_REAL匹配MPI_REAL, 等等。对这个规则, 有一个例外, 将在3.13节中讨论, 类型MPI_PACKED能匹配任何其它类型。
如果由通信操作所使用的数据类型名字相应于宿主程序变量的基本类型,那么宿主程序中该变量的类型匹配通信操作所指定的类型。例如,类型名为MPI_INTEGER的输入匹配Fortran的变量类型INTEGER。在3.2.2节给出Fortran和C的这种对照表。对最后这个规则,有两个例外:类型为名为MPI_BYTE或MPI_PACKED的一个输入能用于匹配任何存储字节(在一个字节地址的机器上), 不论包含这个字节的变量类型是什么。类型MPI_PACKED用于发送己显式打包的数据, 或接收将被显式拆包的数据,看3.13节。类型MPI_BYTE允许我们传送不变的存储中的一个字节的二进制值。
总之,类型匹配规则分为下面三个部分。 .
下面的例子解释了前两种情况。
例子3.1 发送者和接收者指定匹配的类型。
CALL MPI_COMM_RANK(comm, rank, ierr)
IF(rank.EQ.0) THEN
@CALL MPI_SEND(a(1), 10, MPI_REAL, 1, TAG, comm, ierr)
ELSE
@CALL MPI_RECV(b(1), 15, MPI_REAL, 0, tag, comm, status, ierr)
END IF
如果a和b是尺寸大于等于10的实型数组,则这个程序是正确的。(在Fortran中,既使a或b的尺寸小于10, 使用这个程序可能是正确的: 例如, 当a(1)能等价于一个含10个元素的数组。)
例子3.2 发送者和接收者不指定匹配类型。
CALL MPI_COMM_RANK(comm, rank, ierr)
IF(rank.EQ.0) THEN
@CALL MPI_SEND(a(1), 10, MPI_REAL, 1, tag, comm, ierr)
ELSE
@CALL MPI_RECV(b(1), 40, MPI_BYTE, 0, tag, comm, status, ierr)
END IF
这个程序是错误的, 因为发送者和接收者没提供匹配的数据类型参数。
例子3.3 发送者和接收者指定无类型值的通信。
CALL MPI_COMM_RANK(comm, rank, ierr)
IF(rank.EQ.0) THEN
@CALL MPI_SEND(a(1), 40, MPI_BYTE, 1, tag, comm, ierr)
ELSE
@CALL MPI_RECV(b(1), 60, MPI_BYTE, 0, tag, comm, status, ierr)
END IF
无论a和b的尺寸和类型如何, 这个程序是正确的( 这个程序导致存储器存取越界)。
给用户的建议.如果类型为MPI_BYTE的一个缓存作为一个参数传送给MPI_SEND,那么MPI将发送起始地址为buf连续存储空间的数据。当数据布局不是用户所希望的类型时,这可能导致不希望的结果。例如,一些Fortran编译器把类型为CHARACTER的变量作为一个结构来实现, 它包含字符长度和对实际串的指针。在这个环境中,使用MPI_BYTE类型的发送和接收一个Fortran的CHARACTER型变量, 将没有所希望的转换字符串的结果。因为这个,建议用户可能时使用有类型的通信。(给用户的建议结束。)
类型MPI_CHARACTER
类型MPI_CHARACTER匹配Fortran的类型为CHARACTER的一个变量中的一个字符,而不是存储在这个变量中的全部字符。类型为CHARACTER的Fortran得变量或子串好象字符数组一样被传送。在下面的例子中解释这个。
例子3.4 传送Fortran的CHARACTER类型
CHARACTER*10 a
CHARACTER*10 b
CALL MPI_COMM_RANK(comm, rank, ierr)
IF (rank.EQ.0) THEN
@CALL MPI_SEND(a, 5, MPI_CHARACTER, 1, tag, comm, ierr)
ELSE
@CALL MPI_RECV(b(6:10), 5, MPI_CHARACTER, 0, tag, comm, status, ierr)
END IF
进程1中的字符串b的最后五个字符被进程0中的字符串a的前五个字符替代。
基本原理. 另一个选择是对于MPI_CHARACTER类型匹配任意长度的一个字符。 这有时出现错误。
Fortran的一个字符变量是定长的字符串, 没有特别的终结符号。关于怎样表示字符、怎样存储他们的长度没有固定的约定。有些编译器把一个字符参数作为一对参数传送给一个程序,其中之一是保存这个串的地址,另一个是保存串的长度。考虑下面的情况,把导出数据类型(看3.12节)定义的一个通信缓存传 送给一个通信调用。如果这个通信缓存包含CHARACTER类型的变量, 那么关于 他们的长度将不被传送给MPI程序。
这个问题迫使我们给MPI调用提供显式的字符长度的信息。你可以给类型 MPI_CHARACTER 加一个长度参数, 但这并不方便, 通过定义一个适当的导出数 据类型能得到同样的功能。(基本定理结束)。
给用户的建议. 有些编译器把Fortran中CHARACTER类型的参数作为一个结构 传给实际串一个长度和一个指针。在这样的环境中,MPI调用为得到这个串须 间接引用这个指针。(给用户的建议结束)。
Copyright: NPAC, PACT |
![]() ![]() |