您的位置:首页 > 其它

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的体系结构和运行机制有一个基本的了解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: