MPI易于入门

BACKWARD FORWARD


对于基本的应用,MPI同其它消息传送系统一样易于使用。下面的样本代码包含了用于动态负载平衡的主/从应用的全部通信框架。下面的代码描述了一些编写典型并行应用程序所需的函数。

#include <mpi.h>

#define WORKTAG         1
#define DIETAG          2

main(argc, argv)

int                     argc;
char                    *argv[];

{
    int                 myrank;

    MPI_Init(&argc, &argv);     /* MPI 初始化 */
    MPI_Comm_rank(
            MPI_COMM_WORLD,     /* 总使用 */
            &myrank);           /* 进程标识数,0到N-1 */

    if (myrank == 0) {
        master();
    } else {
        slave();
    }

    MPI_Finalize();             /* MPI 结束*/
}

master()

{
    int                 ntasks, rank, work;
    double              result;
    MPI_Status          status;

    MPI_Comm_size(
            MPI_COMM_WORLD,     /* 总使用 */
            &ntasks);           /* #应用程序中的进程 */
/*
 * Seed the slaves.
 */
    for (rank = 1; rank < ntasks; ++rank) {

        work = /* get_next_work_request */;

        MPI_Send(&work,         /* 消息缓冲区 */
                1,              /* 一个数据项 */
                MPI_INT,        /* 数据项是整数 */
                rank,           /* 目的进程标识数 */
                WORKTAG,        /* 用户所选的进程标识 */
                MPI_COMM_WORLD);/* 总使用 */
    }
/*
 * 从任意从属进程接收结果,同时分派新工作
 * 工作请求已用尽
 */
    work = /* 得到下一个工作请求 */;

    while (/* 有效的新工作请求 */) {

        MPI_Recv(&result,       /* 消息缓冲区 */
                1,              /* 一个数据项 */
                MPI_DOUBLE,     /* 双精度实类型 */
                MPI_ANY_SOURCE, /* 从任意发送者接受 */
                MPI_ANY_TAG,    /* 任意消息类型 */
                MPI_COMM_WORLD, /* 总使用 */
                &status);       /* 所接受的消息信息 */

        MPI_Send(&work, 1, MPI_INT, status.MPI_SOURCE,
                WORKTAG, MPI_COMM_WORLD);

        work = /* 得到下一个工作请求 */;
    }
/*
 * 为优异的工作请求接收结果
 */
    for (rank = 1; rank < ntasks; ++rank) {
        MPI_Recv(&result, 1, MPI_DOUBLE, MPI_ANY_SOURCE,
                MPI_ANY_TAG, MPI_COMM_WORLD, &status);
    }
/*
 * 告知所有的从属进程退出
 */
    for (rank = 1; rank < ntasks; ++rank) {
        MPI_Send(0, 0, MPI_INT, rank, DIETAG, MPI_COMM_WORLD);
    }
}

slave()

{
    double              result;
    int                 work;
    MPI_Status          status;

    for (;;) {
        MPI_Recv(&work, 1, MPI_INT, 0, MPI_ANY_TAG,
                MPI_COMM_WORLD, &status);
/*
 * 检查所接受消息的标识
 */
        if (status.MPI_TAG == DIETAG) {
            return;
        }

        result = /* 工作 */;

        MPI_Send(&result, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
    }
}

MPI世界

进程由一个唯一的“标识数”(整数)表示,标识数为数0、1、2、……、N-1。MPI_COMM_WORLD指“MPI应用中的所有进程”,它称为通信子,并且提供消息传递所需的所有信息。可移植库对通信子做更多的工作,以提供大多数其它系统所不能处理的同步保护。

进入和退出MPI

与其它系统一起,提供两个函数来初始化和结束MPI进程:

    MPI_Init(&argc, &argv);
    MPI_Finalize( );

我是谁?他们是谁?

典型地,并行程序中的进程需要知道它是谁(它的标识数)以及其它进程是怎样存在的。一个进程通过调用MPI_Comm_rank( )来发现它自己的标识数:

    int         myrank;

    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

MPI_Comm_size( )返回进程总数:

    int         nprocs;

    MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

发送消息

消息是一组给定数据类型的元素。MPI支持所有的基本数据类型,并且允许更复杂的应用程序在运行时间构造新的数据类型。

消息被发给一个指定的进程,而且用一个由用户说明的标识来标记。标识用来区分不同的由一个进程所能发送/接受的消息类型。在上面的样本代码中,标识用于区分工作和结束消息。

    MPI_Send(buffer, count, datatype, destination, tag,
            MPI_COMM_WORLD);

接受消息

接受进程说明标识和发送进程的标识数。MPI_ANY_TAG和MPI_ANY_SOURCE可选地用于接受任意标识和从任意发送进程而来的消息。

    MPI_Recv(buffer, maxcount, datatype, source, tag,
            MPI_COMM_WORLD, &status);

有关所接受消息的信息在一个状态变量中返回。所接受消息的标识是status.MPI_TAG,发送进程的标识数是status.MPI_SOURCE。

另一函数,在样本代码中没有使用,返回所接受的数据元素的个数。当所接受的元素个数小于‘最大数’时使用它。

        MPI_Get_count(&status, datatype, &nelements);

通过这些函数,你会准备编写任意的应用。在MPI中有许多其它、更特异的函数,但是迄今为止所有这些函数可以在这里提到的函数上构造。

  • LAM / MPI 并行计算/ Ohio Supercomputer Center / [email protected]

  • Copyright: NPACT BACKWARD FORWARD