目录 第一章 MPI 简介 消息传递编程的相关概念 分布式内存 消息传输 进程 消息传递库 发送 / 接收 同步 / 异步 阻塞

Save this PDF as:
 WORD  PNG  TXT  JPG

Size: px
Start display at page:

Download "目录 第一章 MPI 简介 消息传递编程的相关概念 分布式内存 消息传输 进程 消息传递库 发送 / 接收 同步 / 异步 阻塞"

Transcription

1 神威蓝光 计算机系统 MPI 用户手册 国家超级计算济南中心 2011 年 03 月

2 目录 第一章 MPI 简介 消息传递编程的相关概念 分布式内存 消息传输 进程 消息传递库 发送 / 接收 同步 / 异步 阻塞通讯 非阻塞通讯 应用程序缓冲区 系统缓冲区 MPI 环境 头文件 MPI 调用格式 一般 MPI 程序结构 通信因子和组 秩... 6 第二章 MPI 环境管理调用 函数调用 MPI_Init MPI_Comm_size MPI_Comm_rank MPI_Abort MPI_Get_processor_name MPI_Initialized MPI_Wtime MPI_Wtick MPI_Finalize MPI 环境管理例子 C 语言例子 Fortran 语言例子... 9 第三章点对点通信函数 传递参数说明 MPI 消息传递函数参数 缓冲区 (buffer) 元素个数 (count) 数据元素类型 (type) 目的地 (dest) 源 (source) 标识符 (tag) i

3 3.1.8 通信因子 (comm) 状态 (status) 请求 (request) 阻塞消息通信函数 MPI_Send MPI_Recv MPI_Ssend MPI_Bsend MPI_Buffer_attach MPI_Buffer_detach MPI_Rsend MPI_Sendrecv MPI_Wait MPI_Waitany MPI_Waitall MPI_Waitsome MPI_Probe 阻塞消息传递例子 C 程序例子 Fortran 程序例子 非阻塞消息通信函数 MPI_Isend MPI_Irecv MPI_Issend MPI_Ibsend MPI_Irsend MPI_Test MPI_Testany MPI_Testall MPI_Testsome MPI_Iprobe 非阻塞消息传递例子 C 语言例子 Fortran 语言例子 第四章集合通信函数 集合通信函数 MPI_Barrier MPI_Bcast MPI_Scatter MPI_Gather MPI_Allgather MPI_Reduce MPI_Allreduce MPI_Reduce_scatter MPI_Alltoall MPI_Scan 集合通信操作例子 C 语言例子 Fortran 语言例子 例子输出结果 第五章派生数据类型 ii

4 5.1 派生数据类型函数 MPI_Type_contiguous MPI_Type_vector MPI_Type_hvector MPI_Type_indexed MPI_Type_hindexed MPI_Type_struct MPI_Type_extent MPI_Type_commit 连续数据类型的例子 C 语言例子 Fortran 语言例子 例子输出结果 向量派生数据类型例子 C 语言例子 Fortran 语言例子 程序输出结果 索引派生数据类型例子 C 语言例子 Fortran 语言例子 例子输出结果 结构派生数据类型例子 C 语言例子 Fortran 语言例子 例子输出结果 第六章组和通信因子管理函数 组和通信因子管理函数 MPI_Comm_group MPI_Group_rank MPI_Group_size MPI_Group_excl MPI_Group_incl MPI_Group_intersection MPI_Group_union MPI_Group_difference MPI_Group_compare MPI_Group_free MPI_Comm_create MPI_Comm_dup MPI_Comm_compare MPI_Comm_free 组和通信因子管理函数运用例子 C 语言例子 Fortran 语言例子 例子结果输出 第七章虚拟拓扑 iii

5 7.1 虚拟拓扑函数 MPI_Cart_coords MPI_Cart_create MPI_Cart_get MPI_Cart_map MPI_Cart_rank MPI_Cart_shift MPI_Cart_sub MPI_Cartdim_get MPI_Dims_create MPI_Graph_create MPI_Graph_get MPI_Graph_map MPI_Graph_neighbors MPI_Graphdims_get MPI_Topo_test 笛卡儿虚拟拓扑例子 C 语言例子 Fortran 语言例子 例子输出结果 第八章 MPI 运行环境 MPI 用户程序的编译与连接 例子 例子一 (hello 程序 ) 例子二 ( 一个简单的串行程序转换为并行程序 ) 例子三 ( 计算 π 的串行及并行程序 ) iv

6 第一章 MPI 简介 在消息传递库方法的并行编程中, 一组进程所执行的程序是用标准串行语言书写的代码加上用于消息接收和发送的库函数调用 其中,MPI(Message Passing Interface ) 是 1994 年 5 月发布的一种消息传递接口, 它实际上是一个消息传递函数库的标准说明, 吸取了众多消息传递系统的优点, 是目前国际上最流行的并行编程环境之一, 尤其是分布式存储的可缩放并行计算机和工作站网络以及机群的一种编程范例 MPI 具有许多优点 : 具有可移植性和易用性 ; 有完备的异步通信功能 ; 有正式和详细的精确定义 因而为并行软件产业的增长提供了必要的条件 在基于 MPI 编程模型中, 计算是由一个或多个彼此通过调用库函数进行消息收 发通信的进程所组成 在绝大部分 MPI 实现中, 一组固定的进程在程序初始化时生成, 一般情况下, 一个处理器只生成一个进程 这些进程可以执行相同或不同的程序 ( 相应地称为单程序多数据 (SPMD) 或多程序多数据 (MPMD) 模式 ) 进程间的通信可以是点到点的, 也可以是集合的 MPI 只是为程序员提供一个并行环境库, 程序员通过调用 MPI 的库程序来达到程序员所要达到的并行目的,MPI 提供 C 语言和 Fortran 语言接口 MPI 是个复杂的系统, 它包含了 129 个函数 ( 根据 1994 年发布的 MPI 标准 ) 事实上,1997 年修订的标准, 称之为 MPI-2, 已超过 200 个, 目前最常用的也有约 30 个, 然而我们可以只使用其中的 6 个最基本的函数就能编写一个完整的 MPI 程序去求解很多问题 这 6 个基本函数, 包括启动和结束 MPI 环境, 识别进程以及发送和接收消息 : MPI_INIT: 启动 MPI 环境 MPI_Init( ); MPI_FIANLIZE: MPI_Finalize(); 结束 MPI 环境 MPI_COMM_SIZE: MPI_Comm_size( ); 确定进程数 MPI_COMM_RANK: MPI_Comm_rank( ); 确定自己的进程标识符 MPI_SEND: MPI_Send( ); 发送一条消息 MPI_RECV: MPI_Recv( ) 接收一条消息 1

7 一个简单例子 : #include mpi.h main(int argc,char **argv) { int myrank,i,j,k; MPI_Status status; char msg[20]; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&myrank); if(myrank == 0){ strcpy(msg, Hello there ); MPI_Send(msg,strlen(msg) + 1,MPI_CHAR,1,99,MPI_COMM_WORLD); else if(myrank == 1){ MPI_Recv(msg,20,MPI_CHAR,0,99,MPI_COMM_WORLD,&status); printf( Receive message = %s\n,msg); MPI_Finalize(); 其中,MPI_COMM_WORLD 是一个缺省的进程组, 它指明所有的进程都参与计算 1.1 消息传递编程的相关概念 分布式内存 每个处理器都有自己的私有存储空间, 数据从一个处理器到另一个处理器只有通过网络来传输, 而共享存储中的多个处理器可同时访问同一内存单元 分布式系统的示意图如下 : 2

8 1.1.2 消息传输 消息传输是消息数据从一个处理器的内存拷贝到另一个处理器内存的方法 在分布式存储系统中, 数据通常是以消息包的形式通过网络从一个处理器发送到另一个处理器 在消息包中, 包含了消息头控制信息及消息体数据信息两部分 进程 进程是运行在一个处理器上的一个程序, 多个进程可运行在同一个处理器上 在消息传递系统中, 即使是在同一个处理器中运行的多个进程, 他们之间的数据通讯也是通过消息传输来实现的 为了提高效率, 在消息传递系统中, 一般一个处理器只运行一个进程 消息传递库 可连接到用户应用程序中实现消息发送 消息接收以及其他消息传递操作的一组函数的集合 发送 / 接收 消息通信包括数据传输从一个进程 ( 发送 ) 到另一个进程 ( 接收 ) 这就要求两个进程协作完成消息发送和接收过程, 发送进程一般要求指定发送数据的源 数据长度 数据类型及目的地, 而接收操作也要求指定相应的操作与发送相匹配 同步 / 异步 同步发送操作只有等到消息被接收进程安全接收后才完成, 而异步发送操作完成后消息不一定被接收进程接收 3

9 1.1.7 阻塞通讯 阻塞通讯的调用是否完成要依靠某些 事件 : 对于阻塞发送, 数据必须成功的发送或被拷贝到系统缓冲区, 使得该数据缓冲区可被重新使用 ; 对于阻塞接收, 数据必须保证正确接收到本地缓冲区 非阻塞通讯 非阻塞通讯不等待任何通讯事件就可以完成, 它不保证数据已正确发送或接收 发送或接收的数据也许在源方, 也许正在网上, 也许已经到目的方 应用程序缓冲区 在用户应用程序中定义的用于保存发送和接收数据的地址空间 系统缓冲区 保留消息的系统空间 在异步通讯的条件下, 一般需要把数据从应用程序缓冲区中拷贝到系统缓冲区, 保证用户数据不被覆盖 4

10 1.2 MPI 环境 头文件 要求所有包含 MPI 调用得程序文件应加入 : C 包含文件 #include mpi.h Fortran 包含文件 include mpif.h MPI 调用格式 C 程序区分大小写,Fortran 程序不区分大小写 C 程序格式 : rc = MPI_Xxxxx(parameter,... ) 例子 : rc = MPI_Bsend(&buf,count,type,dest,tag,comm) 错误码 : 如果调用成功则 rc 返回 MPI_SUCCESS 格式 : 例子 : 错误码 : Fortran 程序 CALL MPI_XXXXX(parameter,..., ierr) call mpi_xxxxx(parameter,..., ierr) CALL MPI_BSEND(buf,count,type,dest,tag,comm,ierr) 如果调用成功则 ierr 返回 MPI_SUCCESS 在 C 语言描述中, 函数名均冠以 MPI 前缀, 且其首字母需大写 返回的状态值是整数 ; 成功完成的返回代码是 MPI_SUCCESS; 失败时也会定义一组错误代码 编译时的常数均须大写且被定义在文件 mpi.h 中,mpi.h 在任何需调用 MPI 的程序中必须被包含进来 在 Fortran 语言描述中, 函数名也冠以 MPI 前缀, 且必须大写 函数返回代码由一个附加的整数变量表示之 ; 成功完成的返回代码是 MPI_SUCCESS; 失败时也会定义一组错误代码 编译时的常数均须大写且被定义在文件 mpif.h 中, 它在任何需调用 MPI 的程序中必须被包含进来 5

11 1.2.3 一般 MPI 程序结构 包含 MPI 头文件.. 初始化 MPI 环境... 消息交换处理及计算等.. 退出 MPI 环境 通信因子和组 MPI 通过指定通信因子和组来完成各个进程间得通信, 大多数 MPI 调用要求加入通信因子这个参数 MPI_COMM_WORLD 通信因子是在 MPI 环境初始化过程中创建地包含了所有进程, 也是最重要的一个通信因子, 详细的用法下面再介绍 秩 在一个通信因子中, 每个进程都有一个唯一的整数标识符, 该标识符在 MPI 初始化时创建, 有时也称作 进程 ID, 秩是从 0 开始的连续整数 在用户程序中, 经常用秩来判断程序的运行方向 如 : if (rank ==0) { do this else if(rank == 1) { do that 6

12 第二章 MPI 环境管理调用 2.1 函数调用 MPI_Init 初始和启动 MPI 运行环境 每个 MPI 程序必须调用这个函数, 并且这个函数必须在所有调用 MPI 函数之前调用, 而且只能调用一次 对于 C 程序,MPI_Init 必须传递所有的命令行参数, 即要把 argc 和 argv 传递到 MPI 初始化函数中 : MPI_Init (*argc,***argv) MPI_INIT (ierr) MPI_Comm_size 该函数返回与该组通信因子相关的进程数, 通常可以根据全局通信因子 MPI_COMM_WORD 来查询用户程序包含的进程数 : MPI_Comm_size (comm,*size) MPI_COMM_SIZE (comm,size,ierr) IN comm 通信因子 ; OUT size 在该通信因子中包含的进程数目 MPI_Comm_rank 该函数返回该进程在指定通信因子中的秩 (0 ~ 进程数 -1), 一个进程在不同通信因子 中的秩可能不同 : MPI_Comm_rank (comm,*pid) MPI_COMM_RANK (comm,pid,ierr) IN comm 通信因子 ; OUT pid 在该通信因子中本进程的进程号 MPI_Abort 结束所有与该通信因子相关的进程, 但一般来说, 调用该函数后, 所有的进程都退出, 不管该进程是否与该通信因子相关 : MPI_Abort (comm,errorcode) MPI_ABORT (comm,errorcode,ierr) IN comm 通信因子 ; 7

13 OUT errorcode 进程退出时返回的错误号 MPI_Get_processor_name 返回该进程所在的计算节点的名称, 该名称根据网络地址命名,name 缓冲区的大小必 须大于 MPI_MAX_PROCESSOR_NAME, 真正的长度返回在 resultlength 变量中 : MPI_Get_processor_name (*name,*resultlength) MPI_GET_PROCESSOR_NAME (name,resultlength,ierr) OUT name 计算节点名称 ( 即计算节点的 hostname); OUT resultlength 该名称字符串的实际长度 MPI_Initialized 判断 MPI_Init 是否被执行, 返回 true(1),false(0),mpi 应用程序只允许每一个进程仅运行一次 MPI_Init: MPI_Initialized (*flag) MPI_INITIALIZED (flag,ierr) OUT flag MPI_Init 是否运行标识 (0/1) MPI_Wtime 返回调用进程已经执行过地时间, 以秒为单位, 双精度 : MPI_Wtime () MPI_WTIME () MPI_Wtick 按秒返回 MPI_Wtime 的分辨率, 也就是返回一个双精度值 ( 连续时间之间的秒数 ) 例如, 如果时钟由作为按毫秒递增的计数器实现, 则 MPI_Wtick 返回的值是 10-3 MPI_Wtick () MPI_WTICK () MPI_Finalize 结束 MPI 执行环境 该函数一旦被应用程序调用时, 就不能调用 MPI 的其它例行函数 ( 包括 MPI_Init), 用户必须保证在进程调用 MPI_Finalize 之前把与完成进程有关的所有通信结束 MPI_Finalize () MPI_FINALIZE (ierr) 8

14 2.2 MPI 环境管理例子 C 语言例子 #include "mpi.h" #include <stdio.h> int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, rc; rc = MPI_Init(&argc,&argv); if (rc!= 0) { printf ("Error starting MPI program. Terminating.\n"); MPI_Abort(MPI_COMM_WORLD, rc); MPI_Comm_size(MPI_COMM_WORLD,&numtasks); MPI_Comm_rank(MPI_COMM_WORLD,&rank); printf ("Number of tasks= %d My rank= %d\n", numtasks,rank); /******* do some work *******/ MPI_Finalize(); Fortran 语言例子 program simple include 'mpif.h' integer numtasks, rank, ierr, rc call MPI_INIT(ierr) if (ierr.ne. 0) then print *,'Error starting MPI program. Terminating.' call MPI_ABORT(MPI_COMM_WORLD, rc, ierr) end if 9

15 call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) print *, 'Number of tasks=',numtasks,' My rank=',rank C ****** do some work ****** call MPI_FINALIZE(ierr) end 10

16 第三章点对点通信函数 点对点通信 (Point-to-Point Communication) 是 MPI 中比较复杂的一部分, 其数据传送有阻塞和非阻塞两组机制 : 对于阻塞方式, 它必须等到消息从本地送出之后才可以执行后续的语句, 保证了缓冲区等资源的可再用性 ; 对于非阻塞方式, 它不须等到消息从本地送出就可以执行后续的语句, 从而允许通信和计算的重叠, 但非阻塞调用的返回并不保证资源的可再用性 如下图所示, 阻塞和非阻塞有四种模式 : 1. 标准模式, 包括阻塞 ( 标准 ) 发送 MPI_SEND 阻塞( 标准 ) 接收 MPI_RECV 非阻塞 ( 标准 ) 发送 MPI_ISEND 非阻塞( 标准 ) 接收 MPI_IRECV; 2. 缓冲区模式 : 包括阻塞缓冲发送 MPI_BSEND 和非阻塞缓冲发送 MPI_IBSEND; 3. 同步模式 : 包括阻塞同步发送 MPI_SSEND 和非阻塞同步发送 MPI_ISSEND; 4. 就绪模式 : 包括阻塞就绪发送 MPI_RSEND 和非阻塞就绪发送 MPI_IRSEND 在标准通信模式中,MPI 根据当前的状况选取其它三种模式或用户定义的其它模式 ; 缓冲区模式在相匹配的接收未开始的情况下, 总是将送出的消息放在缓冲区内, 这样发送者可以很快地继续计算, 然后由系统处理放在缓冲区中的消息, 但这不仅占用内存, 而且多用了一次内存拷贝 ; 在同步模式中,MPI 必须保证接收者执行到某一点, 这样接收者是必须有确认信息的 ; 在就绪模式下, 系统默认与其相匹配的接收已经调用 标准 1 缓冲 S R 1 同步 S 2 R 3 1 就绪 S 2 R 点到点消息通信四种模式 传递参数说明 MPI 消息传递函数参数 MPI 点对点通信函数的参数格式一般如下所示 : 阻塞发送 MPI_Send(buffer,count,type,dest,tag,comm) 非阻塞发送 MPI_Isend(buffer,count,type,dest,tag,comm,request) 阻塞接收 MPI_Recv(buffer,count,type,source,tag,comm,status) 非阻塞接收 MPI_Irecv(buffer,count,type,source,tag,comm,request) 11

17 3.1.2 缓冲区 (buffer) 指应用程序定义地用于发送或接收数据的缓冲区 元素个数 (count) 指发送或接收数据元素的个数 数据元素类型 (type) MPI 定义了一些缺省的数据类型, 用户也可以根据需要建立自己的数据类型, 其中 MPI_BYTE 和 MPI_PACKED 与 C 或 Fortran 语言的类型不对应 : MPI C 语言数据类型 MPI_CHA signed char R signed short int MPI_SHOR T MPI_INT signed int MPI_LONG signed long int MPI_UNSIGNED_CHAR unsigned char MPI Fortran 语言数据类型 MPI_CHARACTER character(1) MPI_INTEGER integer MPI_UNSIGNED_SHORT unsigned short int MPI_UNSIGNED unsigned int MPI_UNSIGNED_LONG unsigned long int MPI_FLOAT float MPI_REAL real MPI_DOUBLE double MPI_DOUBLE_PRECISION double precision MPI_LONG_DOUBLE long double MPI_COMPLEX complex MPI_LOGICAL logical MPI_BYTE MPI_PACKED 8 binary digits data packed or unpacked with MPI_Pack()/ MPI_Unpack MPI_BYTE MPI_PACKED 8 binary digits data packed or unpacked with MPI_Pack()/ MPI_Unpack 目的地 (dest) 发送进程指定的接收该消息的目的进程, 也就是接收进程的秩 源 (source) 接收进程指定的发送该消息的源进程, 也就是发送进程的秩 如果该值为 MPI_ANY_SOURCE 表示接收任意源进程发来的消息

18 12

19 3.1.7 标识符 (tag) 由程序员指定地为标识一个消息的唯一非负整数值 ( ), 发送操作和接收操作的标识符一定要匹配, 但对于接收操作来说, 如果 tag 指定为 MPI_ANY_TAG 则可与任何发送操作的 tag 相匹配 通信因子 (comm) 包含源与目的进程的一组上下文相关的进程集合, 除非用户自己定义 ( 创建 ) 了新的通信因子, 否则一般使用系统预先定义的全局通信因子 MPI_COMM_WORLD, 它表示所有进程都参与计算 状态 (status) 对于接收操作, 包含了接收消息的源进程 (source) 和消息的标识符 (tag) 在 C 程序中, 这个参数是指向 MPI_Status 结构的指针 ( 如 :status.mpi_source status.mpi_tag); 在 Fortran 程序中, 这个参数是大小为 MPI_STATUS_SIZE 的整数矩阵 ( 如 : status(mpi_source) status(mpi_tag) ) 另外, 实际接收到的消息长度可以通过 MPI_Get_count() 函数从该参数中得到 请求 (request) 这个参数用于非阻塞发送和非阻塞接收操作 由于非阻塞操作返回后, 消息实际上还没有完成到达真正发送或接收, 因此用户可以根据该变量调用其它函数完成消息的实际发送和接收 在 C 程序中, 这个参数是指向 MPI_Request 结构的指针 ; 在 Fortran 程序中, 这个参数是一个整数 3.2 阻塞消息通信函数 这里介绍一些最主要的阻塞消息通信函数 : MPI_Send 该函数是最基本的阻塞发送函数 当函数返回时, 应用程序的发送缓冲区空闲, 可以继续使用 MPI_Send (*buf,count,datatype,dest,tag,comm) MPI_SEND (buf,count,datatype,dest,tag,comm,ierr) IN IN IN buf count datatype 发送数据缓冲区的起始地址 ; 发送数据元素的个数 (>=0); 数据元素的数据类型 ; 13

20 IN IN IN dest tag comm 接收进程的进程号 ; 消息标识 ; 通信因子 MPI_Recv 阻塞接收消息, 直到该消息到达本进程的接收缓冲区后才返回 MPI_Recv (*buf,count,datatype,source,tag,comm,*status) MPI_RECV (buf,count,datatype,source,tag,comm,status,ierr) OUT buf 接收数据缓冲区的起始地址 ; IN IN IN IN IN count datatype source tag comm 接收数据元素的个数 (>=0); 接收数据元素的数据类型 ; 发送进程的进程号或 MPI_ANY_SOURCE; 消息标识或 MPI_ANY_TAG; 通信因子 ; OUT status 接收状态信息 MPI_Ssend 同步阻塞发送 : 发送一个消息, 直到发送进程的缓冲区空闲并且接收进程已经开始接收该消息后返回 MPI_Ssend (*buf,count,datatype,dest,tag,comm,ierr) MPI_SSEND (buf,count,datatype,dest,tag,comm,ierr) MPI_Bsend 缓冲区阻塞发送 : 应用程序首先应申请一个足够大的缓冲区, 然后用 MPI_Buffer_attach 函数加以确认, 当 MPI_Bsend 函数返回时, 消息数据已经从应用程序发送缓冲区拷贝到分配的缓冲区中 MPI_Bsend (*buf,count,datatype,dest,tag,comm) MPI_BSEND (buf,count,datatype,dest,tag,comm,ierr) MPI_Buffer_attach MPI_Buffer_detach 用于分配和释放用于 MPI_Bsend 函数的发送缓冲区,size 参数是以字节为计的缓冲区大小 : MPI_Buffer_attach (*buffer,size) MPI_Buffer_detach (*buffer,size) MPI_BUFFER_ATTACH (buffer,size,ierr) MPI_BUFFER_DETACH (buffer,size,ierr) 14

21 3.2.6 MPI_Rsend 预备方式的阻塞发送 如果能确认接收进程已经开始匹配接收时, 可以使用该发送函数 : MPI_Rsend (*buf,count,datatype,dest,tag,comm) MPI_RSEND (buf,count,datatype,dest,tag,comm,ierr) MPI_Sendrecv 阻塞发送并阻塞接收一个消息 只有当发送缓冲区空并接收缓冲区消息有效后该函数才返回 : MPI_Sendrecv (*sendbuf,sendcount,sendtype,dest,sendtag, *recvbuf,recvcount,recvtype,source,recvtag, comm,*status) MPI_SENDRECV (sendbuf,sendcount,sendtype,dest,sendtag, recvbuf,recvcount,recvtype,source,recvtag, comm,status,ierr) MPI_Wait MPI_Waitany MPI_Waitall MPI_Waitsome MPI_Wait 函数只有当指定的消息发送或接收完成后才返回, 对于多个非阻塞的操作, 程序员可以指定任何一个或一些或全部的消息发送或接收完成后再返回 : MPI_Wait (*request,*status) MPI_Waitany (count,*array_of_requests,*index,*status) MPI_Waitall (count,*array_of_requests,*array_of_statuses) MPI_Waitsome (incount,*array_of_requests,*outcount, array_of_offsets, *array_of_statuses) MPI_WAIT (request,status,ierr) MPI_WAITANY (count,array_of_requests,index,status,ierr) MPI_WAITALL (count,array_of_requests,array_of_statuses, ierr) MPI_WAITSOME (incount,array_of_requests,outcount, array_of_offsets, array_of_statuses,ierr) MPI_Probe 该函数探测一个消息是否完成接收, 只有当探测到消息接收完成后才返回 : MPI_Probe (source,tag,comm,*status) MPI_PROBE (source,tag,comm,status,ierr) 15

22 3.3 阻塞消息传递例子 C 程序例子 #include "mpi.h" #include <stdio.h> int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, dest, source, rc, tag=1; char inmsg, outmsg='x'; MPI_Status Stat; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (rank == 0) { dest = 1; source = 1; rc = MPI_Send(&outmsg, 1, MPI_CHAR, dest, tag, MPI_COMM_WORLD); rc = MPI_Recv(&inmsg, 1, MPI_CHAR, source, tag, MPI_COMM_WORLD, &Stat); else if (rank == 1) { dest = 0; source = 0; rc = MPI_Recv(&inmsg, 1, MPI_CHAR, source, tag, MPI_COMM_WORLD, &Stat); rc = MPI_Send(&outmsg, 1, MPI_CHAR, dest, tag, MPI_COMM_WORLD); MPI_Finalize(); Fortran 程序例子 program ping include 'mpif.h' integer numtasks, rank, dest, source, tag, ierr 16

23 integer stat(mpi_status_size) character inmsg, outmsg tag = 1 call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) & & & & if (rank.eq. 0) then dest = 1 source = 1 outmsg = 'x' call MPI_SEND(outmsg, 1, MPI_CHARACTER, dest, tag, MPI_COMM_WORLD, ierr) call MPI_RECV(inmsg, 1, MPI_CHARACTER, source, tag, MPI_COMM_WORLD, stat, ierr) else if (rank.eq. 1) then dest = 0 source = 0 call MPI_RECV(inmsg, 1, MPI_CHARACTER, source, tag, MPI_COMM_WORLD, stat, err) call MPI_SEND(outmsg, 1, MPI_CHARACTER, dest, tag, MPI_COMM_WORLD, err) endif call MPI_FINALIZE(ierr) end 3.4 非阻塞消息通信函数 这里介绍一些最主要的非阻塞消息通信函数 MPI_Isend 非阻塞发送, 该函数调用后立即返回, 并回送一个发送消息句柄, 发送的消息还在应用程序缓冲区中, 应用程序不能再使用该发送缓冲区, 直到完成 MPI_Wait 或 MPI_Test 函数调用后 : MPI_Isend (*buf,count,datatype,dest,tag,comm,*request) MPI_ISEND (buf,count,datatype,dest,tag,comm,request,ierr) 17

24 3.4.2 MPI_Irecv 非阻塞接收, 该调用返回后, 所要接收的消息未必到本地接收缓冲区中, 直到完成 MPI_Wait 或 MPI_Test 函数调用后, 该接收缓冲区的消息才有效 : MPI_Irecv (*buf,count,datatype,source,tag,comm,*request) MPI_IRECV (buf,count,datatype,source,tag,comm,request,ierr) MPI_Issend 同步方式的无阻塞发送, 类似于 MPI_Isend() 函数去掉 MPI_Wait() 或 MPI_Test() 调用 : MPI_Issend (*buf,count,datatype,dest,tag,comm,*request) MPI_ISSEND (buf,count,datatype,dest,tag,comm,request,ierr) MPI_Ibsend 非阻塞缓冲区发送, 类似于 MPI_Bsend() 函数去掉 MPI_Wait() 或 MPI_Test() 调用 : MPI_Ibsend (*buf,count,datatype,dest,tag,comm,*request) MPI_IBSEND (buf,count,datatype,dest,tag,comm,request,ierr) MPI_Irsend 预备方式的非阻塞发送, 类似于 MPI_Rsend() 函数去掉 MPI_Wait() 或 MPI_Test() 调用, 只有确认接收进程已经开始匹配接收时才可以调用该函数 : MPI_Irsend (*buf,count,datatype,dest,tag,comm,*request) MPI_IRSEND (buf,count,datatype,dest,tag,comm,request,ierr) MPI_Test MPI_Testany MPI_Testall MPI_Testsome MPI_Test 函数用于检测非阻塞发送或接收的消息是否完成, 完成则返回 true(1), 否则返回 false(0), 对于多个非阻塞操作, 可以用 MPI_Testany 或 MPI_Testall 或 MPI_Testsome 调用来检测是否有任一个或所有或一些操作完成 : MPI_Test (*request,*flag,*status) MPI_Testany (count,*array_of_requests,*index,*flag,*status) MPI_Testall (count,*array_of_requests,*flag,*array_of_statuses) MPI_Testsome (incount,*array_of_requests,*outcount,*array_of_offsets, *array_of_statuses) MPI_TEST (request,flag,status,ierr) MPI_TESTANY (count,array_of_requests,index,flag,status,ierr) MPI_TESTALL (count,array_of_requests,flag,array_of_statuses,ierr) MPI_TESTSOME (incount,array_of_requests,outcount, array_of_offsets, array_of_statuses,ierr) 18

25 3.4.7 MPI_Iprobe 0: 该函数探测一个消息接收是否完成, 并立即返回, 如果接收成功参数 falg 为 1, 否则为 MPI_Iprobe (source,tag,comm,*flag,*status) MPI_IPROBE (source,tag,comm,flag,status,ierr) 3.5 非阻塞消息传递例子 C 语言例子 #include "mpi.h" #include <stdio.h> int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, next, prev, buf[2], tag1=1, tag2=2; MPI_Request reqs[4]; MPI_Status stats[4]; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); MPI_Comm_rank(MPI_COMM_WORLD, &rank); prev = rank-1; next = rank+1; if (rank == 0) prev = numtasks - 1; if (rank == (numtasks - 1)) next = 0; MPI_Irecv(&buf[0], 1, MPI_INT, prev, tag1, MPI_COMM_WORLD, &reqs[0]); MPI_Irecv(&buf[1], 1, MPI_INT, next, tag2, MPI_COMM_WORLD, &reqs[1]); MPI_Isend(&rank, 1, MPI_INT, prev, tag2, MPI_COMM_WORLD, &reqs[2]); MPI_Isend(&rank, 1, MPI_INT, next, tag1, MPI_COMM_WORLD, &reqs[3]); MPI_Waitall(4, reqs, stats); MPI_Finalize(); 19

26 3.5.2 Fortran 语言例子 program ringtopo include 'mpif.h' integer numtasks, rank, next, prev, buf(2), tag1, tag2, ierr integer stats(mpi_status_size,4), reqs(4) tag1 = 1 tag2 = 2 call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) prev = rank - 1 next = rank + 1 if (rank.eq. 0) then prev = numtasks - 1 endif if (rank.eq. numtasks - 1) then next = 0 endif & ierr) & ierr) & ierr) & ierr) call MPI_IRECV(buf(1), 1, MPI_INTEGER, prev, tag1, MPI_COMM_WORLD, reqs(1), call MPI_IRECV(buf(2), 1, MPI_INTEGER, next, tag2, MPI_COMM_WORLD, reqs(2), call MPI_ISEND(rank, 1, MPI_INTEGER, prev, tag2, MPI_COMM_WORLD, reqs(3), call MPI_ISEND(rank, 1, MPI_INTEGER, next, tag1, MPI_COMM_WORLD, reqs(4), call MPI_WAITALL(4, reqs, stats, ierr); call MPI_FINALIZE(ierr) end 20

27 第四章集合通信函数 l 集合通信是包含在通信因子中的所有进程都参加操作, 当通信因子为 MPI_COMM_WORLD 时, 应用程序中所有进程都参加 l 集合操作的三种类型 : Ø 同步 (Barrier): 集合中所有进程都到达后, 每个进程再接着运行 ; Ø 数据传递 : 广播 (Broadcast) 分散(Scatter) 收集(Gather) 全部到全部(Alltoall); Ø 归约 (Reduction): 集合中的其中一个进程收集所有进程的数据并计算 ( 如 : 求最大值 求最小值 加 乘等 ); l 集合操作是阻塞的 l 集合操作不带标识符 (tag) 参数 l 只支持 MPI 标准的数据类型, 不支持派生数据类型 4.1 集合通信函数 MPI_Barrier 在组中建立一个同步栅栏 当每个进程都到达 MPI_Barrier 调用后, 程序才接着往下执行 : MPI_Barrier (comm) MPI_BARRIER (comm,ierr) MPI_Bcast 从指定的一个根进程中把数据广播发送给组中的所有其它进程 : 21

28 MPI_Bcast (*buffer,count,datatype,root,comm) MPI_BCAST (buffer,count,datatype,root,comm,ierr) MPI_Scatter 把指定的根进程中的数据分散发送给组中的所有进程 ( 包括自己 ): MPI_Scatter (*sendbuf,sendcnt,sendtype,*recvbuf, recvcnt,recvtype,root,comm) MPI_SCATTER (sendbuf,sendcnt,sendtype,recvbuf, recvcnt,recvtype,root,comm,ierr) MPI_Gather 在组中指定一个进程收集组中所有进程发送来的消息, 这个函数操作与 MPI_Scatter 函数操作相反 : 22

29 MPI_Gather (*sendbuf,sendcnt,sendtype,*recvbuf, recvcount,recvtype,root,comm) MPI_GATHER (sendbuf,sendcnt,sendtype,recvbuf, recvcount,recvtype,root,comm,ierr) MPI_Allgather 在组中的每个进程都收集组中所有进程发送来的消息 : MPI_Allgather (*sendbuf,sendcount,sendtype,*recvbuf, recvcount,recvtype,comm) MPI_ALLGATHER (sendbuf,sendcount,sendtype,recvbuf,recvcount,recvtype,comm,info) MPI_Reduce 在组内所有的进程中, 执行一个归约操作, 并把结果存放在指定的一个进程中 : MPI_Reduce (*sendbuf,*recvbuf,count,datatype,op,root,comm) MPI_REDUCE (sendbuf,recvbuf,count,datatype,op,root,comm,ierr) MPI 缺省定义了如下的归约操作, 用户可根据自己的需要用 MPI_Op_create 函数创建新 的归约操作 : MPI 归约操作 C 语言数据类型 Fortran 语言数据类型 MPI_MAX MPI_MIN MPI_SUM MPI_PROD MPI_LAND 求最大值求最小值和乘积逻辑与 integer, float integer, float integer, float integer, float integer integer, real, complex integer, real, complex integer, real, complex integer, real, complex logical MPI_BAND 按位与 integer, MPI_BYTE integer, MPI_BYTE MPI_LOR 逻辑或 integer logical MPI_BOR 按位或 integer, MPI_BYTE integer, MPI_BYTE MPI_LXOR 逻辑异或 integer logical MPI_BXOR 按位异或 integer, MPI_BYTE integer, MPI_BYTE MPI_MAXLOC 最大值和存储单元 float, double and long double real, complex,double precision 23

30 MPI_MINLOC 最小值和存储单元 float, double and long double real, complex,double precision MPI_Allreduce 执行一个归约操作, 并把结果广播到组内的所有进程中 该操作等价于先执行 MPI_Reduce 操作, 然后再执行 MPI_Bcast: MPI_Allreduce (*sendbuf,*recvbuf,count,datatype,op,comm) MPI_ALLREDUCE (sendbuf,recvbuf,count,datatype,op,comm,ierr) MPI_Reduce_scatter 在组内按元素单位先进行归约操作, 然后把结果分段后分布到组内的其它进程上 该操作等价于先执行 MPI_Reduce 函数, 然后再执行 MPI_ Scatter 函数 : MPI_Reduce_scatter (*sendbuf,*recvbuf,recvcount,datatype, op,comm) MPI_REDUCE_SCATTER (sendbuf,recvbuf,recvcount,datatype, op,comm,ierr) MPI_Alltoall 组中每个进程执行一个发散操作, 发送不同的消息到组内的所有进程上 ( 包括自己 ): MPI_Alltoall (*sendbuf,sendcount,sendtype,*recvbuf, recvcnt,recvtype,comm) MPI_ALLTOALL (sendbuf,sendcount,sendtype,recvbuf, recvcnt,recvtype,comm,ierr) MPI_Scan 用来对分布在进程组上的数据执行前缀归约 : 24

31 MPI_Scan (*sendbuf,*recvbuf,count,datatype,op,comm) MPI_SCAN (sendbuf,recvbuf,count,datatype,op,comm,ierr) 25

32 4.2 集合通信操作例子 C 语言例子 #include "mpi.h" #include <stdio.h> #define SIZE 4 int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, sendcount, recvcount, source; float sendbuf[size][size] = { {1.0, 2.0, 3.0, 4.0, {5.0, 6.0, 7.0, 8.0, {9.0, 10.0, 11.0, 12.0, {13.0, 14.0, 15.0, 16.0 ; float recvbuf[size]; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); if (numtasks == SIZE) { source = 1; 26

33 sendcount = SIZE; recvcount = SIZE; MPI_Scatter(sendbuf,sendcount,MPI_FLOAT,recvbuf,recvcount, MPI_FLOAT,source,MPI_COMM_WORLD); printf("rank= %d Results: %f %f %f %f\n",rank,recvbuf[0], recvbuf[1],recvbuf[2],recvbuf[3]); else printf("must specify %d processors. Terminating.\n",SIZE); MPI_Finalize(); Fortran 语言例子 program scatter include 'mpif.h' integer SIZE parameter(size=4) integer numtasks, rank, sendcount, recvcount, source, ierr real*4 sendbuf(size,size), recvbuf(size) C Fortran stores this array in column major order, so the C scatter will actually scatter columns, not rows. data sendbuf /1.0, 2.0, 3.0, 4.0, & 5.0, 6.0, 7.0, 8.0, & 9.0, 10.0, 11.0, 12.0, & 13.0, 14.0, 15.0, 16.0 / call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) recvbuf, & if (numtasks.eq. SIZE) then source = 1 sendcount = SIZE recvcount = SIZE call MPI_SCATTER(sendbuf, sendcount, MPI_REAL, else endif recvcount, MPI_REAL, source, MPI_COMM_WORLD, ierr) print *, 'rank= ',rank,' Results: ',recvbuf print *, 'Must specify',size,' processors. Terminating.' 27

34 call MPI_FINALIZE(ierr) end 例子输出结果 rank= 0 Results: rank= 1 Results: rank= 2 Results: rank= 3 Results:

35 第五章派生数据类型 l MPI 预定义的基本数据类型 : MPI C 语言数据类型 MPI_CHAR MPI_SHORT MPI_INT MPI_LONG MPI_UNSIGNED_CHAR MPI_UNSIGNED_SHORT MPI_UNSIGNED MPI_UNSIGNED_LONG MPI_FLOAT MPI_DOUBLE MPI_LONG_DOUBLE MPI_BYTE MPI_PACKED MPI Fortran 语言数据类型 MPI_CHARACTER MPI_INTEGER MPI_REAL MPI_DOUBLE_PRECISION MPI_COMPLEX MPI_LOGICAL MPI_BYTE MPI_PACKED l l MPI 的基本数据类型是连续的, 派生数据类型允许定义非连续的数据类型 MPI 提供了基于基本数据类型创建新的派生数据类型的方法 5.1 派生数据类型函数 MPI 中的派生数据类型允许将不连续的数据元素组合在一起, 这种派生数据类型可以使用构造函数构造, 这些派生数据函数包括 : l MPI_TYPE_CONTIGUOUS: 它用来定义由一个或多个连续数据元素组成的数据类型 ; l MPI_TYPE_VECTOR: 它用来定义由一个或多个成块数据元素组成的类型, 这些成块的数据元素是由数组中的恒间距所分开 ; l MPI_TYPE_INDEXED: 它用来定义由一个或多个基本的或先前已定义数据类型的数据块组成的类型, 其中块的长度和块间位移量由数组指定 ; l MPI_TYPE_COMMIT: 它用来提交数据类型, 必须在使用导出数据类型之前使用 MPI_Type_contiguous 最简单的数据类型构造函数 它构造的类型映象包括将一个数据类型复制到连续的位置 : MPI_Type_contiguous (count,oldtype,*newtype) 29

36 MPI_TYPE_CONTIGUOUS (count,oldtype,newtype,ierr) MPI_Type_vector MPI_Type_hvector 允许将一个数据类型复制到由相等间隔块组成的位置的构造函数 每个块通过连接旧数据类型的相同拷贝数而得到 块之间的跨度是旧数据类型长度的倍数 ;MPI_TYPE_HVECTOR 等同于 MPI_TYPE_VECTOR, 除了跨度是用字节而不是用元素度量外 : MPI_Type_vector (count,blocklength,stride,oldtype,*newtype) MPI_TYPE_VECTOR (count,blocklength,stride,oldtype,newtype,ierr) MPI_TYPE_VECTORO 数据类型构造函数 MPI_TYPE_HVECTOR 数据类型构造函数 MPI_Type_indexed MPI_Type_hindexed MPI_Type_indexed 将一个旧的数据类型复制到一系列块中 ( 其中每个块都是旧数据类型的连接 ), 每个块可以含有不同数目的旧数据类型的拷贝, 并且位移也不相同 所有块的位移按旧数据类型的长度为单位度量 ;MPI_TYPE_HINDEXED 等价于 MPI_TYPE_INDEXED, 除了块位移是用字节计而不是用 oldtype 长度的倍数来规定外 : MPI_Type_indexed (count,blocklens[],offsets[],old_type,*newtype) MPI_TYPE_INDEXED (count,blocklens(),offsets(),old_type,newtype,ierr) 30

37 MPI_TYPE_INDEXED 数据类型构造函数 MPI_TYPE_HINDEXED 数据类型构造函数 MPI_Type_struct MPI_TYPE_STRUCT 是最通用的类型构造函数 它将 MPI_PYPE_HINDEXED 进一步通用化, 使之允许每个块含有不同数据类型的复制 其意图是允许将数组结构作为单个数据类型来描述 : MPI_Type_struct (count,blocklens[],offsets[],old_types,*newtype) MPI_TYPE_STRUCT (count,blocklens(),offsets(),old_types,newtype,ierr) MPI_TYPE_STRUCT 数据类型构造函数 MPI_Type_extent MPI_TYPE_EXTENT 返回一个数据类型的长度 该函数除了用于派生数据类型外, 还可以用来查询原始数据类型的长度 例如,MPI_TYPE_EXTENT(MPI_INT,extent) 将在 extent 中返回 int 的字节数, 由 C 返回的相同值称为 Sizeof(int) MPI_Type_extent (datatype,*extent) MPI_TYPE_EXTENT (datatype,extent,ierr) MPI_Type_commit MPI_TYPE_COMMIT 提交数据类型 使系统承认该数据类型的存在, 使之有效 数据类型 31

38 被提交后, 可以重复用于不同数据的通信 MPI_Type_commit (datatype) MPI_TYPE_COMMIT (datatype,ierr) 5.2 连续数据类型的例子 构造一个新数据类型, 把一矩阵中的行当成一个数据类型, 分布到进程组中的其它进程上 : C 语言例子 #include "mpi.h" #include <stdio.h> #define SIZE 4 int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, source=0, dest, tag=1, i; float a[size][size] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0; float b[size]; MPI_Status stat; MPI_Datatype rowtype; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); MPI_Type_contiguous(SIZE, MPI_FLOAT, &rowtype); MPI_Type_commit(&rowtype); if (numtasks == SIZE) { if (rank == 0) { for (i=0; i<numtasks; i++) MPI_Send(&a[i][0], 1, rowtype, i, tag, MPI_COMM_WORLD); MPI_Recv(b, SIZE, MPI_FLOAT, source, tag, MPI_COMM_WORLD, &stat); printf("rank= %d b= %3.1f %3.1f %3.1f%3.1f\n", rank,b[0],b[1],b[2],b[3]); 32

39 else printf("must specify %d processors. Terminating.\n",SIZE); MPI_Finalize(); Fortran 语言例子 program contiguous include 'mpif.h' integer SIZE parameter(size=4) integer numtasks, rank, source, dest, tag, i, ierr real*4 a(0:size-1,0:size-1), b(0:size-1) integer stat(mpi_status_size), columntype C Fortran stores this array in column major order data a /1.0, 2.0, 3.0, 4.0, & 5.0, 6.0, 7.0, 8.0, & 9.0, 10.0, 11.0, 12.0, & 13.0, 14.0, 15.0, 16.0 / call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) call MPI_TYPE_CONTIGUOUS(SIZE, MPI_REAL, columntype, ierr) call MPI_TYPE_COMMIT(columntype, ierr) tag = 1 if (numtasks.eq. SIZE) then if (rank.eq. 0) then do 10 i=0, numtasks-1 call MPI_SEND(a(0,i), 1, columntype, i, tag, MPI_COMM_WORLD,ierr) 10 continue endif source = 0 call MPI_RECV(b, SIZE, MPI_REAL, source, tag, & MPI_COMM_WORLD, stat, ierr) print *,'rank=',rank,' b= ',b else print *, 'Must specify',size,' processors. Terminating.' endif call MPI_FINALIZE(ierr) end 33

40 5.2.3 例子输出结果 rank= 0 b= rank= 1 b= rank= 2 b= rank= 3 b= 向量派生数据类型例子 构造一个新数据类型, 把一矩阵中的列看作一数据类型, 分布到进程组中的其它进程上 : C 语言例子 #include "mpi.h" #include <stdio.h> #define SIZE 4 int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, source=0, dest, tag=1, i; float a[size][size] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 34

41 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0; float b[size]; MPI_Status stat; MPI_Datatype columntype; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); MPI_Type_vector(SIZE, 1, SIZE, MPI_FLOAT, &columntype); MPI_Type_commit(&columntype); if (numtasks == SIZE) { if (rank == 0) { for (i=0; i<numtasks; i++) MPI_Send(&a[0][i], 1, columntype, i, tag, MPI_COMM_WORLD); MPI_Recv(b, SIZE, MPI_FLOAT, source, tag, MPI_COMM_WORLD, &stat); printf("rank= %d b= %3.1f %3.1f %3.1f%3.1f\n", rank,b[0],b[1],b[2],b[3]); else printf("must specify %d processors. Terminating.\n",SIZE); MPI_Finalize(); Fortran 语言例子 program vector include 'mpif.h' integer SIZE parameter(size=4) integer numtasks, rank, source, dest, tag, i, real*4 a(0:size-1,0:size-1), b(0:size-1) integer stat(mpi_status_size), rowtype ierr C Fortran stores this array in column major order data a /1.0, 2.0, 3.0, 4.0, & 5.0, 6.0, 7.0, 8.0, & 9.0, 10.0, 11.0, 12.0, & 13.0, 14.0, 15.0, 16.0 / call MPI_INIT(ierr) 35

42 ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) call MPI_TYPE_VECTOR(SIZE, 1, SIZE, MPI_REAL, rowtype, call MPI_TYPE_COMMIT(rowtype, ierr) tag = 1 if (numtasks.eq. SIZE) then if (rank.eq. 0) then do 10 i=0, numtasks-1 call MPI_SEND(a(i,0), 1, rowtype, i, tag, & MPI_COMM_WORLD, ierr) 10 continue endif source = 0 call MPI_RECV(b, SIZE, MPI_REAL, source, tag, & MPI_COMM_WORLD, stat, ierr) print *,'rank=',rank,' b= ',b else print *, 'Must specify',size,' processors. Terminating.' endif call MPI_FINALIZE(ierr) end 程序输出结果 rank= 0 b= rank= 1 b= rank= 2 b= rank= 3 b=

43 5.4 索引派生数据类型例子 构造一数据类型, 抽取矩阵中的某些元素发散到进程组其它进程上 : C 语言例子 #include "mpi.h" #include <stdio.h> #define NELEMENTS 6 int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, source=0, dest, tag=1, i; int blocklengths[2], displacements[2]; float a[16] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0; 37

44 float b[nelements]; MPI_Status stat; MPI_Datatype indextype; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); blocklengths[0] = 4; blocklengths[1] = 2; displacements[0] = 5; displacements[1] = 12; MPI_Type_indexed(2, blocklengths, displacements, MPI_FLOAT, &indextype); MPI_Type_commit(&indextype); if (rank == 0) { for (i=0; i<numtasks; i++) MPI_Send(a, 1, indextype, i, tag, MPI_COMM_WORLD); MPI_Recv(b, NELEMENTS, MPI_FLOAT, source, tag, MPI_COMM_WORLD, &stat); printf("rank= %d b= %3.1f %3.1f %3.1f %3.1f %3.1f %3.1f\n", rank,b[0],b[1],b[2],b[3],b[4],b[5]); MPI_Finalize(); Fortran 语言例子 program indexed include 'mpif.h' integer NELEMENTS parameter(nelements=6) integer numtasks, rank, source, dest, tag, i, ierr integer blocklengths(0:1), displacements(0:1) real*4 a(0:15), b(0:nelements-1) integer stat(mpi_status_size), indextype data a /1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, & 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 / call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) blocklengths(0) = 4 blocklengths(1) = 2 displacements(0) = 5 38

45 displacements(1) = 12 call MPI_TYPE_INDEXED(2, blocklengths, displacements, MPI_REAL, & indextype, ierr) call MPI_TYPE_COMMIT(indextype, ierr) tag = 1 if (rank.eq. 0) then do 10 i=0, numtasks-1 call MPI_SEND(a, 1, indextype, i, tag, MPI_COMM_WORLD, ierr) 10 continue endif source = 0 call MPI_RECV(b, NELEMENTS, MPI_REAL, source, tag, & MPI_COMM_WORLD, stat, ierr) print *, 'rank= ',rank,' b= ',b call MPI_FINALIZE(ierr) end 例子输出结果 rank= 0 b= rank= 1 b= rank= 2 b= rank= 3 b=

46 5.5 结构派生数据类型例子 创建一结构数据类型, 把用户定义的结构数据发送到进程组中的所有进程上 : C 语言例子 #include "mpi.h" #include <stdio.h> #define NELEM 25 int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, source=0, dest, tag=1, i; typedef struct { float x, y, z; float velocity; int n, type; Particle; Particle p[nelem], particles[nelem]; MPI_Datatype particletype, oldtypes[2]; int blockcounts[2]; /* MPI_Aint type used to be consistent with syntax of */ /* MPI_Type_extent routine */ MPI_Aint offsets[2], extent; MPI_Status stat; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); /* Setup description of the 4 MPI_FLOAT fields x, y, z, velocity */ offsets[0] = 0; oldtypes[0] = MPI_FLOAT; blockcounts[0] = 4; /* Setup description of the 2 MPI_INT fields n, type */ /* Need to first figure offset by getting size of MPI_FLOAT */ MPI_Type_extent(MPI_FLOAT, &extent); offsets[1] = 4 * extent; oldtypes[1] = MPI_INT; 40

47 blockcounts[1] = 2; /* Now define structured type and commit it */ MPI_Type_struct(2, blockcounts, offsets, oldtypes, &particletype); MPI_Type_commit(&particletype); /* Initialize the particle array and then send it to each task */ if (rank == 0) { for (i=0; i<nelem; i++) { particles[i].x = i * 1.0; particles[i].y = i *-1.0; particles[i].z = i * 1.0; particles[i].velocity = 0.25; particles[i].n = i; particles[i].type = i % 2; for (i=0; i<numtasks; i++) MPI_Send(particles, NELEM, particletype, i, tag, MPI_COMM_WORLD); MPI_Recv(p, NELEM, particletype, source, tag, MPI_COMM_WORLD, &stat); /* Print a sample of what was received */ printf("rank= %d %3.2f %3.2f %3.2f %3.2f %d %d\n", rank,p[3].x, p[3].y,p[3].z,p[3].velocity,p[3].n,p[3].type); MPI_Finalize(); Fortran 语言例子 program struct include 'mpif.h' integer NELEM parameter(nelem=25) integer numtasks, rank, source, dest, tag, i, integer stat(mpi_status_size) type Particle sequence real*4 x, y, z, velocity integer n, type end type Particle ierr type (Particle) p(nelem), particles(nelem) 41

48 integer particletype, oldtypes(0:1), blockcounts(0:1), offsets(0:1), extent call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) C C C C particletype, ierr) Setup description of the 4 MPI_REAL fields x, y, z, velocity offsets(0) = 0 oldtypes(0) = MPI_REAL blockcounts(0) = 4 Setup description of the 2 MPI_INTEGER fields n, type Need to first figure offset by getting size of MPI_REAL call MPI_TYPE_EXTENT(MPI_REAL, extent, ierr) offsets(1) = 4 * extent oldtypes(1) = MPI_INTEGER blockcounts(1) = 2 Now define structured type and commit it call MPI_TYPE_STRUCT(2, blockcounts, offsets, oldtypes, call MPI_TYPE_COMMIT(particletype, ierr) C Initialize the particle array and then send it to each task tag = 1 if (rank.eq. 0) then do 10 i=0, NELEM-1 particles(i) = Particle ( 1.0*i, -1.0*i, 1.0*i, 0.25, i, mod(i,2) ) 10 continue do 20 i=0, numtasks-1 call MPI_SEND(particles, NELEM, particletype, i, tag, & MPI_COMM_WORLD, ierr) 20 continue endif & ierr) source = 0 call MPI_RECV(p, NELEM, particletype, source, tag, MPI_COMM_WORLD, stat, print *, 'rank= ',rank,' p(3)= ',p(3) call MPI_FINALIZE(ierr) end 42

49 5.5.3 例子输出结果 rank= rank= rank= rank=

50 第六章组和通信因子管理函数 l 组是一组有秩序的进程的集合, 组中的每一个进程通过唯一的整数秩相关联, 秩的值从 0~N-1(N 为组中的进程数 ) 在 MPI 中, 组在内存中是以一个对象的方式存在着, 并且组总和一个通信因子相关联 l 通信因子包含一个相互之间通信的进程组, 所有的 MPI 通信必须指定一个通信因子 系统缺省的通信因子为 MPI_COMM_WORLD l 对程序员来说, 组和通信因子是一样的, 组函数主要用来指定那些进程可以创建一通信因子 l 使用组和通信因子的主要目的是 : A. 通过一些函数, 允许组织一些进程, 形成新的进程组 B. 允许只在相关的进程间执行集合通讯操作 C. 提供基本的工具来定义虚拟拓扑结构 D. 提供可靠的通信 l 组和通信因子是动态地, 它可以在程序运行过程中创建或释放 l 一个进程可以参加多个组或通信因子, 但它们在组或通信因子中的秩不一定一样 l MPI 提供关于组 通信因子 虚拟拓扑的函数将近 40 多个 l 典型用法 : 1) 使用 MPI_Comm_group 函数从 MPI_COMM_WORLD 因子中提取全局组的句柄 ; 2) 使用 MPI_Group_incl 函数创建一个新组 ( 全局组的子组 ); 3) 根据新组, 使用 MPI_Comm_create 函数创建一个新的通信因子 ; 4) 使用 MPI_Comm_rank 函数确定某一进程在该组中的秩 ; 5) 使用任何 MPI 消息函数使用该新的通信因子 ; 6) 当使用结束后, 用 MPI_Comm_free 和 MPI_Group_free 释放通信因子和组 ; 44

51 6.1 组和通信因子管理函数 MPI_Comm_group 返回与指定通信因子相关联的组的句柄 : MPI_Comm_group (comm,*group) MPI_COMM_GROUP (comm,group,ierr) MPI_Group_rank 返回该进程在指定组中的秩, 如果返回值为 MPI_UNDEFINED, 则标识该进程不在该组内 : MPI_Group_rank (group,*rank) MPI_GROUP_RANK (group,rank,ierr) MPI_Group_size 返回该组中的进程数 : MPI_Group_size (group,*size) MPI_GROUP_SIZE (group,size,ierr) MPI_Group_excl 从指定的组中, 淘汰一些进程后建立一新组 : MPI_Group_excl (group,n,*ranks,*newgroup) MPI_GROUP_EXCL (group,n,ranks,newgroup,ierr) MPI_Group_incl 从指定的组中, 提取一些进程产生一新组 : MPI_Group_incl (group,n,*ranks,*newgroup) MPI_GROUP_INCL (group,n,ranks,newgroup,ierr) MPI_Group_intersection 产生的新组是两个组的交集进程 : MPI_Group_intersection (group1,group2,*newgroup) MPI_GROUP_INTERSECTION (group1,group2,newgroup,ierr) 45

52 6.1.7 MPI_Group_union 产生的新组是两个组的联合 : MPI_Group_union (group1,group2,*newgroup) MPI_GROUP_UNION (group1,group2,newgroup,ierr) MPI_Group_difference 产生的组是两个组中的不同进程组成的 : MPI_Group_difference (group1,group2,*newgroup) MPI_GROUP_DIFFERENCE (group1,group2,newgroup,ierr) MPI_Group_compare 比较两个组, 如果两个组中的成员和秩序都一样则返回 MPI_IDENT, 如果只是成员一样则返回 MPI_SIMILAR, 否则返回 MPI_UNEQUAL: MPI_Group_compare (group1,group2,*result) MPI_GROUP_COMPARE (group1,group2,result,ierr) MPI_Group_free 释放一个用户创建的组 : MPI_Group_free (group) MPI_GROUP_FREE (group,ierr) MPI_Comm_create 该函数根据组和通信因子, 创建一个新的通信因子 : MPI_Comm_create (comm,group,*newcomm) MPI_COMM_CREATE (comm,group,newcomm,ierr) MPI_Comm_dup 复制一个新的通信因子 : MPI_Comm_dup (comm,*newcomm) MPI_COMM_DUP (comm,newcomm,ierr) 46

53 6.1.13MPI_Comm_compare 该函数比较两个通信因子, 找出两个组内通信因子之间的关系 如果两个通信因子中的上下文关系和组都一样, 则返回 MPI_IDENT, 如果上下文关系相同, 而组不相同则返回 MPI_CONGRUENT, 如果上下文关系不相同, 而组相同则返回 MPI_SIMILAR 否则结果为 MPI_UNEQUEL: MPI_Comm_compare (comm1,comm2,*result) MPI_COMM_COMPARE (comm1,comm2,result,ierr) MPI_Comm_free 释放用户创建地通信因子 : MPI_Comm_free (*comm) MPI_COMM_FREE (comm,ierr) 6.2 组和通信因子管理函数运用例子 C 语言例子 #include "mpi.h" #include <stdio.h> #define NPROCS 8 int main(argc,argv) int argc; char *argv[]; { int MPI_Group MPI_Comm rank, new_rank, sendbuf, recvbuf, numtasks, ranks1[4]={0,1,2,3, ranks2[4]={4,5,6,7; orig_group, new_group; new_comm; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); if (numtasks!= NPROCS) { printf("must specify MP_PROCS= %d. Terminating.\n",NPROCS); MPI_Finalize(); exit(0); 47

54 sendbuf = rank; /* Extract the original group handle */ MPI_Comm_group(MPI_COMM_WORLD, &orig_group); /* Divide tasks into two distinct groups based upon rank */ if (rank < NPROCS/2) { MPI_Group_incl(orig_group, NPROCS/2, ranks1, &new_group); else { MPI_Group_incl(orig_group, NPROCS/2, ranks2, &new_group); /* Create new new communicator and then perform collective communications */ MPI_Comm_create(MPI_COMM_WORLD, new_group, &new_comm); MPI_Allreduce(&sendbuf, &recvbuf, 1, MPI_INT, MPI_SUM, new_comm); MPI_Group_rank (new_group, &new_rank); printf("rank= %d newrank= %d recvbuf= %d\n",rank,new_rank,recvbuf); MPI_Finalize(); Fortran 语言例子 program group include 'mpif.h' integer NPROCS parameter(nprocs=8) integer rank, new_rank, sendbuf, recvbuf, numtasks integer ranks1(4), ranks2(4), ierr integer orig_group, new_group, new_comm data ranks1 /0, 1, 2, 3/, ranks2 /4, 5, 6, 7/ call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) if (numtasks.ne. NPROCS) then print *,'Must specify MPROCS= ',NPROCS,' Terminating.' call MPI_FINALIZE(ierr) stop endif sendbuf = rank 48

55 C ierr) C & & & & ierr) Extract the original group handle call MPI_COMM_GROUP(MPI_COMM_WORLD, orig_group, Divide tasks into two distinct groups based upon rank if (rank.lt. NPROCS/2) then call MPI_GROUP_INCL(orig_group, NPROCS/2, ranks1, new_group, ierr) else call MPI_GROUP_INCL(orig_group, NPROCS/2, ranks2, new_group, ierr) endif call MPI_COMM_CREATE(MPI_COMM_WORLD, new_group, new_comm, ierr) call MPI_ALLREDUCE(sendbuf, recvbuf, 1, MPI_INTEGER, MPI_SUM, new_comm, call MPI_GROUP_RANK(new_group, new_rank, ierr) print *, 'rank= ',rank,' newrank= ',new_rank,' recvbuf= ',recvbuf call MPI_FINALIZE(ierr) end 例子结果输出 rank= 7 newrank= 3 recvbuf= 22 rank= 0 newrank= 0 recvbuf= 6 rank= 1 newrank= 1 recvbuf= 6 rank= 2 newrank= 2 recvbuf= 6 rank= 6 newrank= 2 recvbuf= 22 rank= 3 newrank= 3 recvbuf= 6 rank= 4 newrank= 0 recvbuf= 22 rank= 5 newrank= 1 recvbuf= 22 49

56 第七章虚拟拓扑 l MPI 为组内的进程转换拓扑结构提供了一个手段, 该拓扑是虚拟的, 它和并行机的物理结构机处理器的分布状况无关 ; l MPI 提供两个主要的拓扑结构 : 笛卡儿和图 ; l 虚拟拓扑在应用程序特定的通信模式中非常有用 - 并行模式与拓扑结构相匹配 ; l 虚拟拓扑建立在组和通信因子之上 ; 7.1 虚拟拓扑函数 MPI_Cart_coords 笛卡尔转换函数, 把进程序号 ( 秩 ) 转换成坐标 : MPI_Cart_coords (comm,rank,maxdims,*coords[]) MPI_CART_COORDS (comm,rank,maxdims,coords(),ierr) MPI_Cart_create 根据笛卡儿拓扑信息创建一新的通信因子 : MPI_Cart_create (comm_old,ndims,*dims[],*periods, reorder,*comm_cart) MPI_CART_CREATE (comm_old,ndims,dims(),periods,reorder,comm_cart,ierr) MPI_Cart_get 返回与通信因子相关的笛卡尔拓扑的信息 : MPI_Cart_get (comm,maxdims,*dims,*periods,*coords[]) MPI_CART_GET (comm,maxdims,dims,periods,coords(),ierr) MPI_Cart_map 返回由 MPI 系统推荐的笛卡尔映象图, 为了更好地将该应用的虚拟通信图映射到物理机器拓扑上, 该调用是全局的 MPI_Cart_map (comm_old,ndims,*dims[],*periods[],*newrank) MPI_CART_MAP (comm_old,ndims,dims(),periods(),newrank,ierr) MPI_Cart_rank 该函数将逻辑进程坐标转换成进程序号 ( 秩 ), 这些序号由点对点通信的程序使用 : 50

57 MPI_Cart_rank (comm,*coords[],*rank) MPI_CART_RANK (comm,coords(),rank,ierr) MPI_Cart_shift 该函数完成笛卡尔移位操作, 根据移位坐标和移位步骤大小 ( 正数或负数 ) 输入条件确定移位操作, 返回移位的源和目的的秩 : MPI_Cart_shift (comm,direction,displ,*source,*dest) MPI_CART_SHIFT (comm,direction,displ,source,dest,ierr) MPI_Cart_sub 该函数用来将通信因子组分成较低维笛卡尔子网格的子组, 并可为每个子组构造一个具有相关子网格笛卡尔拓扑的通信因子 : MPI_Cart_sub (comm,*remain_dims[],*comm_new) MPI_CART_SUB (comm,remain_dims(),comm_new,ierr) MPI_Cartdim_get 返回与通信因子相关的笛卡尔结构的维数 这可用来向其他笛卡尔查询函数提供数组的正确大小 : MPI_Cartdim_get (comm,*ndims) MPI_CARTDIM_GET (comm,ndims,ierr) MPI_Dims_create 该函数帮助用户在每个坐标方向选择一种进程的均衡分布, 这取决于被均衡的组中的进程数以及由用户指定的限制条件 使用该函数的一种可能方法是将所有进程 (MPI_COMM_WORLD 的组大小 ) 分成一个 n 维的拓扑 : MPI_Dims_create (nnodes,ndims,*dims[]) MPI_DIMS_CREATE (nnodes,ndims,dims(),ierr) MPI_Graph_create 返回一个与图拓扑信息相连的新通信因子 : MPI_Graph_create (comm_old,nnodes,*index[],*edges[], reorder,*comm_graph) MPI_GRAPH_CREATE (comm_old,nnodes,index(),edges(), reorder,comm_graph,ierr) 51

58 7.1.11MPI_Graph_get 该函数返回与通信因子相关联的图拓扑信息 : MPI_Graph_get (comm,maxindex,maxedges,*index[],*edges[]) MPI_GRAPH_GET (comm,maxindex,maxedges,index(),edges(),ierr) MPI_Graph_map 返回由图的拓扑信息印象 : MPI_Graph_map (comm_old,nnodes,*index[],*edges[],*newrank) MPI_GRAPH_MAP (comm_old,nnodes,index(),edges(),newrank,ierr) MPI_Graph_neighbors 返回与指定进程相关的临近节点数组 : MPI_Graph_neighbors (comm,rank,maxneighbors,*neighbors[]) MPI_GRAPH_NEIGHBORS (comm,rank,maxneighbors,neighbors(),ierr) MPI_Graphdims_get 返回图中的节点数和边数 : MPI_Graphdims_get (comm,*nnodes,*nedges) MPI_GRAPHDIMS_GET (comm,nnodes,nedges,ierr) MPI_Topo_test 返回赋与通信因子的拓扑类型 : MPI_GRAPH 图拓扑 MPI_CART 笛卡尔拓扑 MPI_UNDEFINED 没有拓扑 MPI_Topo_test (comm,*top_type) MPI_TOPO_TEST (comm,top_type,ierr) 7.2 笛卡儿虚拟拓扑例子 用 16 个进程建立一个 4*4 的笛卡儿拓扑结构, 每个进程与临近的 4 个进程交换秩 : 52

59 7.2.1 C 语言例子 #include "mpi.h" #include <stdio.h> #define SIZE 16 #define UP 0 #define DOWN 1 #define LEFT 2 #define RIGHT 3 int main(argc,argv) int argc; char *argv[]; { int numtasks, rank, source, dest, outbuf, i, tag=1, inbuf[4]={mpi_proc_null,mpi_proc_null,mpi_proc_null, MPI_PROC_NULL,, nbrs[4], dims[2]={4,4, periods[2]={0,0, reorder=0, coords[2]; MPI_Request reqs[8]; MPI_Status stats[8]; MPI_Comm cartcomm; %d\n", MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD, &numtasks); if (numtasks == SIZE) { MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, reorder, &cartcomm); MPI_Comm_rank(cartcomm, &rank); MPI_Cart_coords(cartcomm, rank, 2, coords); MPI_Cart_shift(cartcomm, 0, 1, &nbrs[up], &nbrs[down]); MPI_Cart_shift(cartcomm, 1, 1, &nbrs[left], &nbrs[right]); outbuf = rank; for (i=0; i<4; i++) { dest = nbrs[i]; source = nbrs[i]; MPI_Isend(&outbuf, 1, MPI_INT, dest, tag, MPI_COMM_WORLD, &reqs[i]); MPI_Irecv(&inbuf[i], 1, MPI_INT, source, tag, MPI_COMM_WORLD, &reqs[i+4]); MPI_Waitall(8, reqs, stats); printf("rank= %d coords= %d %d neighbors(u,d,l,r)= %d %d %d %d\n", rank,coords[0],coords[1],nbrs[up],nbrs[down],nbrs[left], nbrs[right]); printf("rank= %d inbuf(u,d,l,r)= %d %d %d 53

60 rank,inbuf[up],inbuf[down],inbuf[left],inbuf[right]); else printf("must specify %d processors. Terminating.\n",SIZE); MPI_Finalize(); Fortran 语言例子 program cartesian include 'mpif.h' integer SIZE, UP, DOWN, LEFT, RIGHT parameter(size=16) parameter(up=1) parameter(down=2) parameter(left=3) parameter(right=4) integer numtasks, rank, source, dest, outbuf, i, tag, ierr, & inbuf(4), nbrs(4), dims(2), coords(2), & stats(mpi_status_size, 8), reqs(8), cartcomm, & periods(2), reorder data inbuf /MPI_PROC_NULL,MPI_PROC_NULL,MPI_PROC_NULL, & MPI_PROC_NULL/, dims /4,4/, tag /1/, & periods /0,0/, reorder /0/ call MPI_INIT(ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numtasks, ierr) & & & ierr) if (numtasks.eq. SIZE) then call MPI_CART_CREATE(MPI_COMM_WORLD, 2, dims, periods, reorder, cartcomm, ierr) call MPI_COMM_RANK(cartcomm, rank, ierr) call MPI_CART_COORDS(cartcomm, rank, 2, coords, ierr) print *,'rank= ',rank,'coords= ',coords call MPI_CART_SHIFT(cartcomm, 0, 1, nbrs(up), nbrs(down), ierr) call MPI_CART_SHIFT(cartcomm, 1, 1, nbrs(left), nbrs(right), ierr) outbuf = rank do i=1,4 dest = nbrs(i) source = nbrs(i) call MPI_ISEND(outbuf, 1, MPI_INTEGER, dest, tag, MPI_COMM_WORLD, reqs(i), ierr) call MPI_IRECV(inbuf(i), 1, MPI_INTEGER, source, tag, MPI_COMM_WORLD, reqs(i+4), 54

61 enddo call MPI_WAITALL(8, reqs, stats, ierr) print *,'rank= ',rank,' coords= ',coords, ' neighbors(u,d,l,r)= ',nbrs print *,'rank=',rank,' ', ' inbuf(u,d,l,r)= ',inbuf else print *, 'Must specify',size,' processors. Terminating.' endif call MPI_FINALIZE(ierr) end 例子输出结果 rank= 0 coords= 0 0 neighbors(u,d,l,r)= rank= 0 inbuf(u,d,l,r)= rank= 1 coords= 0 1 neighbors(u,d,l,r)= rank= 1 inbuf(u,d,l,r)= rank= 2 coords= 0 2 neighbors(u,d,l,r)= rank= 2 inbuf(u,d,l,r)= rank= 14 coords= 3 2 neighbors(u,d,l,r)= rank= 14 inbuf(u,d,l,r)= rank= 15 coords= 3 3 neighbors(u,d,l,r)= rank= 15 inbuf(u,d,l,r)=

62 第八章 MPI 运行环境 8.1 MPI 用户程序的编译与连接 Ø C 编译器为 :mpicc Ø Ø Fortran 编译器为 :mpif77 或 mpif90 运行 (MPI 作业提交 ) 见 作业管理用户手册 8.2 例子 例子一 (hello 程序 ) l 编辑代码 % vi hello.c #include mpi.h main(argc,argv) int argc; char **argv; { char msg[20]; int myrank,tag = 99; MPI_Status status; l MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&myrank); /*find my rank */ if ( myrank == 0) { strcpy( msg, Hello there ); MPI_Send( msg, strlen(msg), MPI_CHAR, 1, tag, MPI_COMM_WORLD); else if ( myrank == 1) { MPI_Recv(msg, 20, MPI_CHAR, 0,tag, MPI_COMM_WORLD, &status); printf( received %s\n,msg); MPI_Finalize(); 编译连接源代码 % mpicc o hello hello.c 56

63 生成可执行代码 hello 例子二 ( 一个简单的串行程序转换为并行程序 ) /* 串行程序 */ #include <stdio.h> void main(argc,argv) int argc; char *argv[]; { int A,B,C,D,E,F,G; B = 1; C = 2; F = 3; G = 4; A = B + C; E = F + G; D = A - E; printf("d=%d\n",d); return; /* MPI 并行程序 3 个进程 */ #include "mpi.h" #include <stdio.h> void main(argc,argv) int argc; char *argv[]; { int A,B,C,D,E,F,G; int numprocs,myid; 57

64 MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myid); if (numprocs!= 3) { printf("numproces must equal to 3!\n"); MPI_Finalize(); return; if(myid == 1) { B = 1; C = 2; A = B + C; MPI_Send(&A,1,MPI_INT,0,80,MPI_COMM_WORLD); else if (myid ==2) { F = 3; G = 4; E = F + G; MPI_Send(&E,1,MPI_INT,0,80,MPI_COMM_WORLD); else if (myid == 0) { MPI_Recv(&A,1,MPI_INT,1,80,MPI_COMM_WORLD); MPI_Recv(&E,1,MPI_INT,2,80,MPI_COMM_WORLD); D = A - E; printf("d = %d\n",d); MPI_Finalize(); /* MPI 并行程序 2 个进程 */ #include "mpi.h" #include <stdio.h> void main(argc,argv) int argc; char *argv[]; 58

65 { int A,B,C,D,E,F,G; int numprocs,myid; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myid); if (numprocs!= 2) { printf("numproces must equal to 2!\n"); MPI_Finalize(); return; if (myid == 0) { B = 1; C = 2; A = B + C; MPI_Recv(&E,1,MPI_INT,1,80,MPI_COMM_WORLD); D = A - E; printf("d = %d\n",d); else if (myid == 1) { F = 3; G = 4; E = F + G; MPI_Send(&E,1,MPI_INT,0,80,MPI_COMM_WORLD); MPI_Finalize(); 例子三 ( 计算 π 的串行及并行程序 ) 用数值积分法求 的函数表达式, 就是区间 [0,1] 内与函数曲线 4/(1+X 2 ) 组成的面积, 此面积就是 π 的近似值, 为此先将区间 [0,1] 划分成 N 个等间隔的子区间, 每个子区间的宽度为 1/N; 然后计算出各个子区间中点处的函数值 ; 再将各个子区间面积相加就可以得出 的近似值 59

66 计算 π 的表达式 : 1 P = 1 + ò 4 dx» å 0 x 2 0 < i ö i N 1 + ç N è ø 4 * 1 N é ù ê ú P» 4 ê ê æ + N ç + æ æ æ N - + ö ú ú ö ö ö ( 1) 0.5 ê1 è N 1 ç N 1 ç N 1 ç N ú ë ø è ø è ø è ø û /* 计算 π 的 C 语言串行程序 */ #include <stdio.h> #include <math.h> #define N main() { double local,pi=0.0,w; long i; w = 1.0/N; for ( i = 0; i < N; i++) { local = (i + 0.5) * w; pi = pi / (1.0 + local * local); printf( pi is %f\n,pi*w);

67 60

68 #include "mpi.h" #include <stdio.h> #include <math.h> double f(a) double a; { return (4.0 / (1.0 + a*a)); void main(argc,argv) int argc; char *argv[]; { int done = 0, n, myid, numprocs, i; double PI25DT = ; double mypi, pi, h, sum, x; double startwtime, endwtime; int namelen; char processor_name[mpi_max_processor_name]; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myid); MPI_Get_processor_name(processor_name,&namelen); fprintf(stderr,"process %d on %s\n", myid, processor_name); n = 0; while (!done) { if (myid == 0) { printf("enter the number of intervals: (0 quits) "); scanf("%d",&n); startwtime = MPI_Wtime(); MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); if (n == 0) 61

PowerPoint 演示文稿

PowerPoint 演示文稿 第四讲 消息传递编程接口 MPI 一 MPI 编程基础 主要内容 MPI 安装 程序编译与运行 MPI 编程基础 MPI 程序基本结构 MPI 数据类型 消息发送和接收 MPI 一些常用函数 MPI 介绍 Message Passing Interface 消息传递编程标准, 目前最为通用的并行编程方式 提供一个高效 可扩展 统一的并行编程环境 MPI 是一个库, 不是一门语言,MPI 提供库函数

More information

投影片 1

投影片 1 平行運算簡介 / 實例操作企鵝也會的 MPICH 研究員 : 鄧偉華 wade@nchc.org.tw 什麼是平行計算 傳統 : 單一程序 單一 CPU 什麼是平行計算 ( 續 ) 平行計算 程序切割 多 CPUs 為什麼要平行計算 簡省時間 解決大型問題 即時性 使用更多來自網路上的資源 使用大量 便宜 PCs 取代超級電腦 記憶體不足 平行計算種類 Flynn's taxonomy 多處理器架構

More information

第7章-并行计算.ppt

第7章-并行计算.ppt EFEP90 10CDMP3 CD t 0 t 0 To pull a bigger wagon, it is easier to add more oxen than to grow a gigantic ox 10t 0 t 0 n p Ts Tp if E(n, p) < 1 p, then T (n) < T (n, p) s p S(n,p) = p : f(x)=sin(cos(x))

More information

Parallel Programming with MPI

Parallel Programming  with MPI MPI 并行编程入门 中国科学院计算机网络信息中心超级计算中心 聚合通信 定义 三种通信方式 聚合函数列表 同步 广播 收集 散发 全散发收集 归约 定义 communicator 1 3 4 5 0 2 一个通信器的所有进程参与, 所有进程都调用聚合通信函数 MPI 系统保证聚合通信函数与点对点调用不会混淆 聚合通信不需要消息标号 聚合通信函数都为阻塞式函数 聚合通信的功能 : 通信 同步 计算等

More information

Parallel Programming with MPI

Parallel Programming  with MPI MPI 并行编程入门 中国科学院计算机网络信息中心超级计算中心 参考材料 张林波清华大学出版社莫则尧科学出版社都志辉清华大学出版社 消息传递平台 MPI 什么是 MPI (Message Passing Interface) 是函数库规范, 而不是并行语言 ; 操作如同库函数调用 是一种标准和规范, 而非某个对它的具体实现 (MPICH 等 ), 与编程语言无关 是一种消息传递编程模型, 并成为这类编程模型的代表

More information

大綱介紹 MPI 標準介紹 MPI 的主要目標 Compiler & Run 平行程式 MPICH 程式基本架構 點對點通訊 函數介紹 集體通訊 函數介紹

大綱介紹 MPI 標準介紹 MPI 的主要目標 Compiler & Run 平行程式 MPICH 程式基本架構 點對點通訊 函數介紹 集體通訊 函數介紹 MPI 平行程式設計 勁智數位科技股份有限公司 技術研發部林勝峰 sflin@infowrap.com.tw 大綱介紹 MPI 標準介紹 MPI 的主要目標 Compiler & Run 平行程式 MPICH 程式基本架構 點對點通訊 函數介紹 集體通訊 函數介紹 MPI (Message Passing Interface) Version1.0:June, 1994. Version1.1:June,

More information

PowerPoint 演示文稿

PowerPoint 演示文稿 第六讲 消息传递编程接口 MPI 三 MPI 数据类型 1 MPI 数据类型 MPI 数据类型定义 MPI 数据类型的大小 上下界 域及相关函数 MPI 新数据类型的创建 提交与释放 MPI 数据的打包与解包 2 MPI 数据类型 MPI 原始数据类型 MPI 消息传递通常只能处理连续存放的同一类型的数据 MPI 自定义数据类型 如果需要发送或接收具有复杂结构的数据时, 可以使用自定义数据类型 使用自定义数据类型的好处

More information

目 录 参 考 材 料 1 第 一 章 预 备 知 识 2 1.1 高 性 能 并 行 计 算 机 系 统 简 介.................................. 2 1.1.1 微 处 理 器 的 存 储 结 构.................................

目 录 参 考 材 料 1 第 一 章 预 备 知 识 2 1.1 高 性 能 并 行 计 算 机 系 统 简 介.................................. 2 1.1.1 微 处 理 器 的 存 储 结 构................................. MPI 并 行 编 程 讲 稿 张 林 波 中 国 科 学 院 数 学 与 系 统 科 学 研 究 院 科 学 与 工 程 计 算 国 家 重 点 实 验 室 1999 年 7 月 ( 最 后 修 订 :2012 年 7 月 ) i 目 录 参 考 材 料 1 第 一 章 预 备 知 识 2 1.1 高 性 能 并 行 计 算 机 系 统 简 介..................................

More information

PowerPoint 演示文稿

PowerPoint 演示文稿 机群应用开发 并行编程原理及程序设计 Parallel Programming: Fundamentals and Implementation 占杰 zhanjie@dawningcomcn 曙光信息产业有限公司 2010 年 1 月 2010 年 1 月 1 参考文献 黄铠, 徐志伟著, 陆鑫达等译 可扩展并行计算技术, 结构与编程 北京 : 机械工业出版社, P33~56,P227~237,

More information

mpi

mpi MPI I II MPI FORTRAN C MPI MPI C /FORTRAN MPI MPI MPI MPI MPI MPI-2 MPI-1 MPI-2 MPI MPI ...IX...XI... XII...XIV... XVII...1 1...2 1.1...2 1.1.1...2 1.1.2...3 1.2...4 1.3...5 2...6 2.1...6 2.2...7 2.3...8

More information

07-1.indd

07-1.indd 1 02 04 13 16 19 21 24 28 32 38 44 49 54 12 27 57 58 59 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Å 20 ELMFIRE Procon LES EFSS CohortComparator GPaw 21 22 ï ~ ~ ~ ~ 23 24 25 26 CPU usage time (s) time

More information

C++ 程式設計

C++ 程式設計 C C 料, 數, - 列 串 理 列 main 數串列 什 pointer) 數, 數, 數 數 省 不 不, 數 (1) 數, 不 數 * 料 * 數 int *int_ptr; char *ch_ptr; float *float_ptr; double *double_ptr; 數 (2) int i=3; int *ptr; ptr=&i; 1000 1012 ptr 數, 數 1004

More information

mannal

mannal 高 性 能 集 群 计 算 机 使 用 说 明 书 版 本 1.0.8 高 性 能 计 算 研 究 组 编 2008 年 3 月 12 日 第 1 页 共 30 页 高 性 能 集 群 计 算 机... 1 使 用 说 明 书... 1 高 性 能 计 算 集 群 使 用 说 明... 3 1. 集 群 系 统 概 述... 3 2. 使 用 方 法... 5 1. 登 录 方 法... 5 2.MPI

More information

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.06.doc

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.06.doc 2 5 8 11 0 13 1. 13 2. 15 3. 18 1 23 1. 23 2. 26 3. 28 2 36 1. 36 2. 39 3. 42 4. 44 5. 49 6. 51 3 57 1. 57 2. 60 3. 64 4. 66 5. 70 6. 75 7. 83 8. 85 9. 88 10. 98 11. 103 12. 108 13. 112 4 115 1. 115 2.

More information

chap07.key

chap07.key #include void two(); void three(); int main() printf("i'm in main.\n"); two(); return 0; void two() printf("i'm in two.\n"); three(); void three() printf("i'm in three.\n"); void, int 标识符逗号分隔,

More information

FY.DOC

FY.DOC 高 职 高 专 21 世 纪 规 划 教 材 C++ 程 序 设 计 邓 振 杰 主 编 贾 振 华 孟 庆 敏 副 主 编 人 民 邮 电 出 版 社 内 容 提 要 本 书 系 统 地 介 绍 C++ 语 言 的 基 本 概 念 基 本 语 法 和 编 程 方 法, 深 入 浅 出 地 讲 述 C++ 语 言 面 向 对 象 的 重 要 特 征 : 类 和 对 象 抽 象 封 装 继 承 等 主

More information

3 5 5 3 1 9 1 0 1 0 1 0 1 0 1 2 1 2 1 2 2 π 202 2 3.14 100 2 628 a 12 15 x a 20 = 9 2 2 3 2 4 2 5 2 1 2 2 ìí ì í à á à á á à è é è ò è à ó ò ì ù à í

More information

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数 复习 类的复用 组合 (composition): has-a 关系 class MyType { public int i; public double d; public char c; public void set(double

More information

untitled

untitled 不 料 料 例 : ( 料 ) 串 度 8 年 數 串 度 4 串 度 數 數 9- ( ) 利 數 struct { ; ; 數 struct 數 ; 9-2 數 利 數 C struct 數 ; C++ 數 ; struct 省略 9-3 例 ( 料 例 ) struct people{ char name[]; int age; char address[4]; char phone[]; int

More information

OOP with Java 通知 Project 4: 4 月 19 日晚 9 点

OOP with Java 通知 Project 4: 4 月 19 日晚 9 点 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 4: 4 月 19 日晚 9 点 复习 类的复用 组合 (composition): has-a 关系 class MyType { public int i; public double d; public char c; public void set(double x) { d

More information

C 1 # include <stdio.h> 2 int main ( void ) { 4 int cases, i; 5 long long a, b; 6 scanf ("%d", & cases ); 7 for (i = 0;i < cases ;i ++) 8 { 9

C 1 # include <stdio.h> 2 int main ( void ) { 4 int cases, i; 5 long long a, b; 6 scanf (%d, & cases ); 7 for (i = 0;i < cases ;i ++) 8 { 9 201 201 21 ( ) 1. C pa.c, pb.c, 2. C++ pa.cpp, pb.cpp Compilation Error long long cin scanf Time Limit Exceeded 1: A 1 B 1 C 5 D RPG 10 E 10 F 1 G II 1 1 201 201 C 1 # include 2 int main ( void

More information

mpic_2002

mpic_2002 C 語言 MPI 平行計算程式設計 編著 : 鄭守成 期 間 : 民國 91 年 1 月 1 日 電話 : (03) 5776085 x 305 E-mail : c00tch00@nchc.gov.tw 1 C 語言 MPI 平行計算程式設計...1 第一章 前言...4 1.1 MPI 平行計算軟體...5 1.2 國家高速電腦中心的平行計算環境...6 1.3 在 IBM SP2 上如何使用

More information

( CIP) /. :, ( ) ISBN TP CIP ( 2005) : : : : * : : 174 ( A ) : : ( 023) : ( 023)

( CIP) /. :, ( ) ISBN TP CIP ( 2005) : : : : * : : 174 ( A ) : : ( 023) : ( 023) ( CIP) /. :, 2005. 2 ( ) ISBN 7-5624-3339-9.......... TP311. 1 CIP ( 2005) 011794 : : : : * : : 174 ( A ) :400030 : ( 023) 65102378 65105781 : ( 023) 65103686 65105565 : http: / /www. cqup. com. cn : fxk@cqup.

More information

科学计算的语言-FORTRAN95

科学计算的语言-FORTRAN95 科 学 计 算 的 语 言 -FORTRAN95 目 录 第 一 篇 闲 话 第 1 章 目 的 是 计 算 第 2 章 FORTRAN95 如 何 描 述 计 算 第 3 章 FORTRAN 的 编 译 系 统 第 二 篇 计 算 的 叙 述 第 4 章 FORTRAN95 语 言 的 形 貌 第 5 章 准 备 数 据 第 6 章 构 造 数 据 第 7 章 声 明 数 据 第 8 章 构 造

More information

Microsoft Word - CIN-DLL.doc

Microsoft Word - CIN-DLL.doc 6.3. 调 用 动 态 链 接 库 (DLL) 相 对 于 CIN 来 讲,NI 更 推 荐 用 户 使 用 DLL 来 共 享 基 于 文 本 编 程 语 言 开 发 的 代 码 除 了 共 享 或 重 复 利 用 代 码, 开 发 人 员 还 能 利 用 DLL 封 装 软 件 的 功 能 模 块, 以 便 这 些 模 块 能 被 不 同 开 发 工 具 利 用 在 LabVIEW 中 使 用

More information

, 7, Windows,,,, : ,,,, ;,, ( CIP) /,,. : ;, ( 21 ) ISBN : -. TP CIP ( 2005) 1

, 7, Windows,,,, : ,,,, ;,, ( CIP) /,,. : ;, ( 21 ) ISBN : -. TP CIP ( 2005) 1 21 , 7, Windows,,,, : 010-62782989 13501256678 13801310933,,,, ;,, ( CIP) /,,. : ;, 2005. 11 ( 21 ) ISBN 7-81082 - 634-4... - : -. TP316-44 CIP ( 2005) 123583 : : : : 100084 : 010-62776969 : 100044 : 010-51686414

More information

提纲 1 2 OS Examples for 3

提纲 1 2 OS Examples for 3 第 4 章 Threads2( 线程 2) 中国科学技术大学计算机学院 October 28, 2009 提纲 1 2 OS Examples for 3 Outline 1 2 OS Examples for 3 Windows XP Threads I An Windows XP application runs as a seperate process, and each process may

More information

Microsoft PowerPoint - ds-1.ppt [兼容模式]

Microsoft PowerPoint - ds-1.ppt [兼容模式] http://jwc..edu.cn/jxgl/ HomePage/Default.asp 2 说 明 总 学 时 : 72( 学 时 )= 56( 课 时 )+ 16( 实 验 ) 行 课 时 间 : 第 1 ~14 周 周 学 时 : 平 均 每 周 4 学 时 上 机 安 排 待 定 考 试 时 间 : 课 程 束 第 8 11 12 章 的 内 容 为 自 学 内 容 ; 目 录 中 标 有

More information

3.1 num = 3 ch = 'C' 2

3.1 num = 3 ch = 'C' 2 Java 1 3.1 num = 3 ch = 'C' 2 final 3.1 final : final final double PI=3.1415926; 3 3.2 4 int 3.2 (long int) (int) (short int) (byte) short sum; // sum 5 3.2 Java int long num=32967359818l; C:\java\app3_2.java:6:

More information

ò í ú ó ì à ò è 5500 500 2 5500 x 23 50 2 5 2 5 9 5 10 9 5 9 9 4 4 10 64 9 9 74 10 1 5 2 1 9 5 5 4 9 7 1 5 1 3 2 1 3 1 5 1 3 1 5 1 1 5 1 3 1 1 1 4 1 4 2 40 40 1

More information

ú á à à á á è ù? ì í ì á ì ò é? é à ì? à ó é à ì à à ì é í ì è? à ì á ú ó á á ì ù ì è ù

More information

ò ú ó ó ú ó ú ó ú ú ó G L E = G W à è í ü í ü ü á á á á á á á á

More information

(i) (ii) (iii) (i) (ii) (iii) (iv) 1. 2

(i) (ii) (iii) (i) (ii) (iii) (iv) 1. 2 696 14A.35(1) 14A 1 (i) (ii) (iii) (i) (ii) (iii) (iv) 1. 2 14A.35(1) 14A.35(1) 14A.35(1) 14A.35(1) 2. 2.1 A. 3 (i) (ii) (iii) (iv) (1) (i)(ii) 4.5 6.5 6.5 7 (2) (iii) (a) 74 (b) 500 4 (3) (iv) PID PID

More information

ò ó ì á è ó

ò ó ì á è ó ò ó ì á è ó à à è ì è á ó ì à ì à à à á ì ó à ì ì è ó à ú ì í í á ù ò ò í ì ó à ò ú ó ì à à à à à à í á ì ù ù è ù è ò è ù é à

More information

ì

ì ì ó à á à í é é è ú à ú ù è í ù è á ú é ù í é à ú á à í ó ò è ì ì é à à á ò à ú è ó á à í ù ú ì ì í ì á è ù ù ò ó á ì ì à è á á ì à ó è ì á ì ì à é ì ó é à ú í ì í á à á

More information

ttian

ttian í á é ì ì ì ó á ú è ù ó è á á é ì ú á á ò á è è ó é è ì á à á

More information

1989 67 1993 125 305 1989 251 1964 8 1990 231 1983 608 1987 207 1990 6 ú é ì à í à ó 1990 51 é í í ù è ì ò ú à ù ó ú è í à ì è è è í á ó ì á á ò ì á ò

More information

int *p int a 0x00C7 0x00C7 0x00C int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++;

int *p int a 0x00C7 0x00C7 0x00C int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++; Memory & Pointer trio@seu.edu.cn 2.1 2.1.1 1 int *p int a 0x00C7 0x00C7 0x00C7 2.1.2 2 int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++; 2.1.3 1. 2. 3. 3 int A,

More information

ú ì à ì ù ù é à à à í ú ì ì à í à é ì ó à è à ù ì é á ù ú ò ù ù ò

More information

í í à ù à à í è è ú ì á á í à ú á è á ú à é à ù ú ì ì ì ò í è ì ì í ì ì ì è ì ì à é ó ò ó ú é ì ù ì í ó è ì à è á à ì à à à í í é á à ù ì ò ì é ú í í à à à à

More information

ó ú à ù á í í ì ì ù á ù í í ò ó ú ù à ì ì è á í í ì è á ù è ì à ú ì ù ì í à ì ì ó ì ì è ì è á ó à ó ò é ú? à á á ú á í é ì é ì á à á ù á à ò á ò é ù? ì

More information

030 í á ì ú è ì à é ù ò í í ú ù ù á í í ì ù ó ù ì è à é é ú í ì ù ì è ò á à ì ì ì ì ì á ú ì é í í é ò í ì é è ú ú í é ú è à è è à è ó à ò ù à à ù ó ì ì ì à à ù à á ú á ì á ù ù è

More information

é ú í í à á í à ù à é ó à è á ù á à à ì á á à é í á ò è ì í ì ù à é ì ì à à è ù é à ù à é ú ì ú ù 1 1 3 4

More information

è

è è à à à í á à à ì ú ú á ú ú ì ì í ù í à ú è ò ò ì ù ì à ì à í ì ì è è è é à ì é é á è í í à ì è ì ú í ù ì ò è à í ì à á è ì ó ú è é é ì é ì ì ì ú ó ì à ú á

More information

ò à í é ì è ì é á à è à è è ì á á à à à

More information

Chapter #

Chapter # 第三章 TCP/IP 协议栈 本章目标 通过本章的学习, 您应该掌握以下内容 : 掌握 TCP/IP 分层模型 掌握 IP 协议原理 理解 OSI 和 TCP/IP 模型的区别和联系 TCP/IP 介绍 主机 主机 Internet TCP/IP 早期的协议族 全球范围 TCP/IP 协议栈 7 6 5 4 3 应用层表示层会话层传输层网络层 应用层 主机到主机层 Internet 层 2 1 数据链路层

More information

á á á ú é ó é é á í í á ú á é á á í í é

More information

á à è á à í ú á è é ì á ò ò ú ó ì à í ù à à ó á ú è è à á ì à ó é ì é íí ù á ì ú ó è à è è è ú ú è è á ì à ò ù à ú ò é è à à è ì è ì à í à ó

More information

nooog

nooog C : : : , C C,,, C, C,, C ( ), ( ) C,,, ;,, ; C,,, ;, ;, ;, ;,,,, ;,,, ; : 1 9, 2 3, 4, 5, 6 10 11, 7 8, 12 13,,,,, 2008 1 1 (1 ) 1.1 (1 ) 1.1.1 ( ) 1.1.2 ( ) 1.1.3 ( ) 1.1.4 ( ) 1.1.5 ( ) 1.2 ( ) 1.2.1

More information

二零零六年一月二十三日會議

二零零六年一月二十三日會議 附 件 B 有 关 政 策 局 推 行 或 正 在 策 划 的 纾 缓 及 预 防 贫 穷 措 施 下 文 载 述 有 关 政 策 局 / 部 门 为 加 强 纾 缓 及 预 防 贫 穷 的 工 作, 以 及 为 配 合 委 员 会 工 作, 在 过 去 十 一 个 月 公 布 及 正 在 策 划 的 新 政 策 和 措 施 生 福 利 及 食 物 局 (i) 综 合 儿 童 发 展 服 务 2.

More information

厨房小知识(四)

厨房小知识(四) I...1...2...3...4...4...5...6...6...7...9...10... 11...12...12...13...14...15...16...17...18...18...19...22...22 II...23...24...25...26...27...27...28...29...29...30...31...31?...32...32...33?...33...34...34...35...36...36...37...37...38...38...40

More information

妇女更年期保健.doc

妇女更年期保健.doc ...1...2...3...5...6...7 40...8... 11...13...14...16...17...19...20...21...26...29...30...32 I ...34...35...37...41...46...50...51...52...53...54...55...58...64...65 X...67...68...70...70...74...76...78...79

More information

小儿传染病防治(上)

小儿传染病防治(上) ...1...2...3...5...7...7...9... 11...13...14...15...16...32...34...34...36...37...39 I ...39...40...41...42...43...48...50...54...56...57...59...59...60...61...63...65...66...66...68...68...70...70 II

More information

<4D6963726F736F667420576F7264202D2031303430333234B875B9B5A448ADFBBADEB27AA740B77EA4E2A5555FA95EAED6A641ADD75F2E646F63>

<4D6963726F736F667420576F7264202D2031303430333234B875B9B5A448ADFBBADEB27AA740B77EA4E2A5555FA95EAED6A641ADD75F2E646F63> 聘 僱 人 員 管 理 作 業 參 考 手 冊 行 政 院 人 事 行 政 總 處 編 印 中 華 民 國 104 年 3 月 序 人 事 是 政 通 人 和 的 關 鍵 是 百 事 俱 興 的 基 礎, 也 是 追 求 卓 越 的 張 本 唯 有 人 事 健 全, 業 務 才 能 順 利 推 動, 政 府 施 政 自 然 績 效 斐 然 本 總 處 做 為 行 政 院 人 事 政 策 幕 僚 機

More information

女性青春期保健(下).doc

女性青春期保健(下).doc ...1...4...10... 11...13...14...15...17...18...19...20...21...22...23...24...26...27...30...31 I ...32...33...36...37...38...40...41...43...44...45...46...47...50...51...51...53...54...55...56...58...59

More information

避孕知识(下).doc

避孕知识(下).doc ...1...3...6...13...13...14...15...16...17...17...18...19...19...20...20...23...24...24...25 I ...25...26...26...27...28...28...29...30...30...31...32...34...35 11...36...37...38...40...42...43...44...44...46

More information

孕妇饮食调养(下).doc

孕妇饮食调养(下).doc ...1...2...5...9 7...9...14...15...16...18...22...23...24...25...27...29...31...32...34 I ...35...36...37...39...40...40...42...44...46...48...51...52...53...53...54...55...56...56...58...61...64 II ...65...66...67...68...69...70...71...72...73...74...75...76...77...80...83...85...87...88

More information

禽畜饲料配制技术(一).doc

禽畜饲料配制技术(一).doc ( ) ...1...1...4...5...6...7...8...9...10... 11...13...14...17...18...21...23...24...26 I ...28 70...30...33...35...36...37...39...40...41...49...50...52...53...54...56...58...59...60...67...68...70...71

More information

中老年保健必读(十一).doc

中老年保健必读(十一).doc ...1...2...4...6...8...9...10...12...14...15...17...18...20...22...23...25...27...29 I ...30...32...35...38...40...42...43...45...46...48...52...55...56...59...62...63...66...67...69...71...74 II ...76...78...79...81...84...86...87...88...89...90...91...93...96...99...

More information

i

i i ii iii iv v vi 1 2 3 4 5 (b) (a) (b) (c) = 100% (a) 6 7 (b) (a) (b) (c) = 100% (a) 2 456 329 13% 12 120 7.1 0.06% 8 9 10 11 12 13 14 15 16 17 18 19 20 (a) (b) (c) 21 22 23 24 25 26 27 28 29 30 31 =

More information

怎样使孩子更加聪明健康(七).doc

怎样使孩子更加聪明健康(七).doc ...1...2...2...4...5 7 8...6...7...9 1 3... 11...12...14...15...16...17...18...19...20...21...22 I II...23...24...26 1 3...27...29...31...31...33...33...35...35...37...39...41...43...44...45 3 4...47...48...49...51...52

More information

i

i i ii iii iv v vi 1 g j 2 3 4 ==== ==== ==== 5 ==== ======= 6 ==== ======= 7 ==== ==== ==== 8 [(d) = (a) (b)] [(e) = (c) (b)] 9 ===== ===== ===== ===== ===== ===== 10 11 12 13 14 15 16 17 ===== [ ] 18 19

More information

马太亨利完整圣经注释—雅歌

马太亨利完整圣经注释—雅歌 第 1 页 目 录 雅 歌 简 介... 2 雅 歌 第 一 章... 2 雅 歌 第 二 章... 10 雅 歌 第 三 章... 16 雅 歌 第 四 章... 20 雅 歌 第 五 章... 25 雅 歌 第 六 章... 32 雅 歌 第 七 章... 36 雅 歌 第 八 章... 39 第 2 页 雅 歌 简 介 我 们 坚 信 圣 经 都 是 神 所 默 示 的 ( 提 摩 太 后 书

More information

(1) (2) (3) 1. (1) 2

(1) (2) (3) 1. (1) 2 0386 71.32% 14A 1 (1) (2) (3) 1. (1) 2 (a) (b) (i) (ii) (iii) 3 (iv) (a) (b) (c) (d) 6% 4 2013 3 26 [2013]624 10 5 2013 6 28 [2013]1246 2015 3 [2015]351 0.2 6 [2015]748 180C 7 * * 8 14A (2) 417,800,000

More information

NOWOER.OM m/n m/=n m/n m%=n m%n m%=n m%n m/=n 4. enum string x1, x2, x3=10, x4, x5, x; 函数外部问 x 等于什么? 随机值 5. unsigned char *p1; unsigned long *p

NOWOER.OM m/n m/=n m/n m%=n m%n m%=n m%n m/=n 4. enum string x1, x2, x3=10, x4, x5, x; 函数外部问 x 等于什么? 随机值 5. unsigned char *p1; unsigned long *p NOWOER.OM /++ 程师能 评估. 单项选择题 1. 下 描述正确的是 int *p1 = new int[10]; int *p2 = new int[10](); p1 和 p2 申请的空间 的值都是随机值 p1 和 p2 申请的空间 的值都已经初始化 p1 申请的空间 的值是随机值,p2 申请的空间 的值已经初始化 p1 申请的空间 的值已经初始化,p2 申请的空间 的值是随机值 2.

More information