MPI入门基础(程序欣赏)
2017-03-27 21:58
253 查看
从几个简单的MPI程序领你入门
读程序学习编程,是成长最快的方式。hello程序看MPI程序结构
/** * 我是世界上引用率最高的程序,hiahia! */ #include <stdio.h> #include <mpi.h> int main(int argc, char * argv[]) { int myrank; // 初始化MPI环境 //从这里可以看到,一般MPI指令是MPI_跟一个大写字母 //开始的单词,后面都是小写字母。 MPI_Init(&argc, &argv); // 获取当前进程在通信器MPI_COMM_WORLD中的进程号 MPI_Comm_rank(MPI_COMM_WORLD, &myrank); printf("myrank = %d: Hello, world!\n", myrank); MPI_Finalize(); return 0; }
点对点消息接发
/** * 进程0向进程1发送一个整数. */ #include <stdio.h> #include <stdlib.h> #include <mpi.h> #define N 100000 int main (int argc, char *argv[]) { int i, myrank; int a ; MPI_Status status; // 初始化MPI环境 MPI_Init (&argc, &argv); // 初始化数组 for (i = 0; i < N; i++) { a[i] = -1; } // 获取当前进程在通信器MPI_COMM_WORLD中的进程号 MPI_Comm_rank (MPI_COMM_WORLD, &myrank); //让进程号为0的,数组中每一个元素都为100. if (myrank == 0) { for (i = 0; i < N; i++) { a[i] = 100; } // 进程0向进程1发送一个整数 MPI_Send (&a, N, MPI_INT, 1, 99, MPI_COMM_WORLD); } else { fprintf (stderr, "myrank = %d, before recv. a[0] = %d\n", myrank, a[0]); // 进程1从进程0接收一个整数 //MPI_Recv语句多了一个&status。 MPI_Recv (&a, N, MPI_INT, 0, 99, MPI_COMM_WORLD, &status); fprintf (stderr, "myrank = %d, after recv. a[0] = %d\n\n", myrank, a[0]); } // 结束MPI环境,测试程序分配两个进程即可,多了其他进程陷入接收的等待中…… MPI_Finalize (); return 0; }
体会进程号
/** * 输出一个进程的两个“进程号”: * - 在操作系统中的进程号; * - 在MPI环境中,某一通信器中的进程号。 */ #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <mpi.h> int main (int argc, char *argv[]) { int myrank, myrank_1, nprocs; // 初始化MPI环境 MPI_Init (&argc, &argv); // 每个进程都获取它在通信器“MPI_COMM_WORLD”中的进程号 //MPI_COMM_WORLD全大写,是通信器名称。 MPI_Comm_rank (MPI_COMM_WORLD, &myrank); // 每个进程都获取它在通信器“MPI_COMM_SELF”中的进程号 MPI_Comm_rank (MPI_COMM_SELF, &myrank_1); // 每个进程都获取通信器“MPI_COMM_WORLD”中的进程总数 MPI_Comm_size (MPI_COMM_WORLD, &nprocs); //tderr -- 标准错误输出设备 ,不用深究这东西,mpi格式化打印语句,使用fprintf时照着往上打就行了。getpid()获取进程的识别码。 fprintf (stderr, "process id = %d, myrank in MPI_COMM_WORLD = %d, myrank in MPI_COMM_SELF = %d\n", getpid (), myrank, myrank_1); // 结束MPI环境 MPI_Finalize (); return 0; }
两个小例子看tag标签在消息传递中的作用
例子一: /** * 相同的"源"和"目的"之间, 不同的消息可以通过不同的标签来识别. */ #include <stdio.h> #include <stdlib.h> #include <mpi.h>//MPI都要加上MPI头文件。 #define N 1 int main (int argc, char *argv[]) { int myrank, dest; int my_int , get_int ; //要接收,有个MPI_Status类型的status是必要的。 MPI_Status status; MPI_Init (&argc, &argv); MPI_Comm_rank (MPI_COMM_WORLD, &myrank); my_int[0] = myrank; get_int[0] = myrank + 1; dest = (myrank == 0) ? (1) : (0);//0给1,1给0。 #if 1 //0号进程传输0和1给1号进程 if (myrank == 0) { MPI_Send (my_int, N, MPI_INT, dest, 99, MPI_COMM_WORLD); MPI_Send (get_int, N, MPI_INT, dest, 99, MPI_COMM_WORLD); } else { // 1号进程的1和2位置分别接收来自0号进程的0和1,如何对应呢?可以动手一试。tag相同,一般按先后顺序发收。 printf ("myrank %d: my_int = %d, \tget_int = %d\n", myrank, my_int[0], get_int[0]); MPI_Recv (get_int, N, MPI_INT, dest, 99, MPI_COMM_WORLD, &status); MPI_Recv (my_int, N, MPI_INT, dest, 99, MPI_COMM_WORLD, &status); printf ("myrank %d: my_int = %d, \tget_int = %d\n", myrank, my_int[0], get_int[0]); } #endif MPI_Finalize (); return 0; } 例子二: /** * 多个进程向同一进程发送消息时,不同的消息到达目的进程的顺序不确定。 * 此时,可以通过不同的标签来识别来自不同进程的消息. */ #include <stdio.h> #include <stdlib.h> #include <mpi.h> #define N 1 int main (int argc, char *argv[]) { int myrank, dest; int my_int , int_from_1 , int_from_2 ; MPI_Status status; MPI_Init (&argc, &argv); MPI_Comm_rank (MPI_COMM_WORLD, &myrank); my_int[0] = myrank * 111; if (myrank == 1) { dest = 0; MPI_Send (my_int, N, MPI_INT, dest, 99, MPI_COMM_WORLD); } else if (myrank == 2) { dest = 0; MPI_Send (my_int, N, MPI_INT, dest, 99, MPI_COMM_WORLD); } else { MPI_Recv (int_from_1, N, MPI_INT, MPI_ANY_SOURCE, 99, MPI_COMM_WORLD, &status); //接收者可以给source指定一个任意值MPI_ANY_SOURCE //,标识任何进程发送的消息都可以接受,即本接收操作 //可以匹配任何进程发送的消息,但其它的要求还必须满足,比如tag的匹配。 MPI_Recv (int_from_2, N, MPI_INT, MPI_ANY_SOURCE, 99, MPI_COMM_WORLD, &status); printf ("myrank %d: int_from_1 = %d, \tint_from_2 = %d\n", myrank, int_from_1[0], int_from_2[0]); } //与前不同,由于1号进程和2号进程发消息的速度指不定谁快,所以在消息tag一样的情况的下,接收具有随机性。 //从这个程序进一步体会tag在消息传递中的作用。 MPI_Finalize (); return 0; }
计时函数的使用
/** * 统计各进程消耗的墙上时间. */ #include <unistd.h> #include <stdio.h> #include <mpi.h> int main (int argc, char *argv[]) { int myrank, nprocs, name_len, flag; double start_time, end_time; char host_name[10]; // 检测MPI环境是否已经初始化. MPI_Initialized (&flag); fprintf (stderr, "flag: %d\n", flag); // 初始化MPI环境 MPI_Init (&argc, &argv); // 获取当前进程在通信器MPI_COMM_WORLD中的进程号 MPI_Comm_rank (MPI_COMM_WORLD, &myrank); // 获取通信器MPI_COMM_WORLD中的进程数 MPI_Comm_size (MPI_COMM_WORLD, &nprocs); // 获取处理器名称,和名字长度 MPI_Get_processor_name(host_name, &name_len); if (myrank == 0) { fprintf (stderr, "precision of MPI_Wtime(): %f.\n", MPI_Wtick()); // 计时的精度 fprintf (stderr, "host name: %s\n", host_name); } //获取墙上时间 start_time = MPI_Wtime(); sleep(myrank * 3); //获取墙上时间 end_time = MPI_Wtime(); fprintf (stderr, "myrank: %d. I have slept %f seconds.\n", myrank, end_time - start_time); // 结束MPI环境 MPI_Finalize (); return 0; }// mpi 的计时函数的使用,好好体会。
通过观摩这几个简单的程序,对MPI的体系结构和运行机制有一个基本的了解。
相关文章推荐
- 循环控制结构程序01 - 零基础入门学习C语言16
- 循环控制结构程序03 - 零基础入门学习C语言18
- 第一个程序03 - 零基础入门学习汇编语言22
- 包含多个段的程序02 - 零基础入门学习汇编语言30
- 包含多个段的程序02 - 零基础入门学习汇编语言30
- 【学习笔记】零基础C#窗口程序开发入门
- 第一个程序 - 零基础入门学习Delphi01
- 第一个程序02 - 零基础入门学习汇编语言21
- 第一个程序01 - 零基础入门学习汇编语言20
- 包含多个段的程序03 - 零基础入门学习汇编语言31
- 零基础易语言入门教程(三)之了解控制台程序
- 循环控制结构程序05 - 零基础入门学习C语言20
- 循环控制结构程序04 - 零基础入门学习C语言19
- 第一个程序02 - 零基础入门学习汇编语言21
- 循环控制结构程序06 - 零基础入门学习C语言21
- 循环控制结构程序02 - 零基础入门学习C语言17
- 循环控制结构程序04 - 零基础入门学习C语言19
- 循环控制结构程序06 - 零基础入门学习C语言21
- 包含多个段的程序01 - 零基础入门学习汇编语言29
- 第一个程序 - 零基础入门学习Delphi01