4.11 搜索(Scan) |
MPI_SCAN(sendbuf, recvbuf, count, datatype, op, comm) IN sendbuf 发送消息缓冲区的起始地址(可变) OUT recvbuf 接收消息缓冲区的起始地址(可变) IN count 输入缓冲区中元素的个数(整型) IN datatype 输入缓冲区中元素的类型(句柄) IN op 操作(句柄) IN comm 通信子(句柄) int MPI_Scan(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) MPI_SCAN(SENDBUF, RECVBUF, COUNT, DATATYPE, OP, COMM, IERROR) <type> SENDBUF(*), RECVBUF(*) INTEGER COUNT, DATATYPE, OP, COMM, IERROR
MPI_SCAN常用于对分布于组中的数据作前置归约操作.此操作将序列号为0,... ,i(包括i)的进程发送缓冲区的值的归约结果存入序列号为i 的进程的接收消息缓冲区中,这种操作支持的类型、语义以及对发送及接收缓冲区的限制和MPI_REDUCE相同.
例4.22: 本例用一个用户自定义的操作进行段扫描,一个段扫描将一组值和一组逻辑量作为输入,其中逻辑值将输入分割成不同的段.例如对于以下数据:
操作符产生的结果是:
这里
注意这是一个非交换操作.它的C代码如下:
typedef struct { double val; int log; } SegScanPair; /* 用户自定义的函数 */ void segScan(SegScanPair *in, SegScanPair *inout, int *len, MPI_Datatype *dptr) { int i; SegScanPair c; for (i=0; i<*len; ++i) { if (in->log == inout->log) c.val = in->val + inout->val; else c.val = inout->val; c.log = inout->log; *inout = c; in++; inout++; } }
注意用户自定义操作的参数inout与操作的右端操作数相对应,当使用这个操作符时,应注意将它描述成一个非交换的,如下所示:
int i,base; SeqScanPair a, answer; MPI_Op myOp; MPI_Datatype type[2] = {MPI_DOUBLE, MPI_INT}; MPI_Aint disp[2]; int blocklen[2] = {1, 1}; MPI_Datatype sspair; /* 告之MPI SegScanPair类型是如何定义的 */ MPI_Address(a, disp); MPI_Address(a.log, disp+1); base = disp[0]; for (i=0; i<2; ++i) disp[i] -= base; MPI_Type_struct(2, blocklen, disp, type, &sspair); MPI_Type_commit(&sspair); /* 生成段扫描的用户op */ MPI_Op_create(segScan, False, &myOp); ...... MPI_Scan(a, answer, 1, sspair, myOp, root, comm);
Copyright: NPACT |