MPI入门基础(程序欣赏)

从几个简单的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[N];
  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[N], get_int[N];
  //要接收,有个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[N], int_from_1[N], int_from_2[N];
  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的体系结构和运行机制有一个基本的了解。

  • 10
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陆嵩

有打赏才有动力,你懂的。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值