MPI学习——jacabi迭代(非阻塞通信与重复阻塞通信)

本文深入探讨了MPI中的Jacobi迭代法,并重点讲解了非阻塞通信的概念及其在迭代过程中的应用,揭示了如何利用非阻塞通信提升并行计算效率。
      为了实现计算与通信的最大重叠 一个通用的原则就是 尽早开始通信 尽晚完成通信
在开始通信和完成通信之间进行计算 这样通信启动得越早 完成得越晚 就有可能有更多
的计算任务可以和通信重叠 也使通信可以在计算任务执行期间完成 而不需要专门的等待
时间
      为此 修改Jacobi迭代过程如下
        1 计算迭代任务中下次需要通信的数据
        2 启动非阻塞通信 传递这些数据 转下一次迭代
        3 计算剩余的迭代部分

        4 完成非阻塞通信

#include<mpi.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 8;
const int SIZE = N / 4;
const int T = 2;


int main()
{
    double matrix1[SIZE+2][N], matrix[SIZE+2][N];
    int myid;
    MPI_Status status[4];
    MPI_Request request[4];


    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);


    memset(matrix1, 0, sizeof matrix1);
    memset(matrix2, 0, sizeof matrix2);


    //赋值边界数据
    if(0 == myid)
        for(int j = 0; j < N; j++)
            matrix1[1][j] = matrix[2][j] = N;
    if(3 == myid)
        for(int j = 0; j < N; j++)
            matrix1[SIZE][j] = matrix2[SIZE][j] = N;
    for(int i = 1; i < SIZE+1; i++)
        matrix1[i][0] = matrix1[i][N-1] = matrix2[0] = matrix2[N-1] = N;

      
    //引入虚拟进程简化代码
    int up_proc_id = myid==0 ? MPI_PROC_NULL : myid - 1;
    int down_proc_id = myid==3 ? MPI_PROC_NULL : myid + 1;
    //jacobi迭代
    int t, row, col;
    for(t = 0; t < T; t++)
    {
        if(0 == myid)
            for(col = 1; col < N-1; col++)
                matrix2[SIZE][col] = 0.25 * (matrix1[SIZE][col-1] + matrix1[SIZE][col+1] + matrix1[SIZE-1][col] + matrix[SIZE+1][col]);
        else if(3 == myid)
            for(col = 1; col < N-1; col++)
                matrix2[1][col] = 0.25 * (matrix1[1][col-1] + matrix1[1][col+1] + matrix1[0][col] + matrix1[2][col]);;
        else
            for(col = 1; col < N-1; col++) // 中间的矩阵块
                matrix2[SIZE][col] = 0.25 * (matrix1[SIZE][col-1] + matrix1[SIZE][col+1] + matrix1[SIZE+1][col] + matrix1[SIZE-1][col]);
                matrix2[1][col] = 0.25 * (matrix1[1][col-1] + matrix1[1][col+1] + matrix1[2][col] + matrix1[0][col]);
        //利用非阻塞通信传递边界数据
        int tag1 = 1, tag2 = 2;
        MPI_Isend(&matrix2[1][0], N, MPI_DOUBLE, up_proc_id, tag1, MPI_COMM_WORLD, request[0]);
        MPI_Isend(&matrix2[SIZE][0], N, MPI_DOUBLE, down_proc_id, tag2, MPI_COMM_WORLD, request[1]);
        MPI_Irecv(&matrix1[SIZE+1][0], N, MPI_DOUBLE, down_proc_id, tag1, MPI_COMM_WORLD, request[2]);
        MPI_Irecv(&matrix1[0][0], N, MPI_DOUBLE, up_proc_id, tag1, MPI_COMM_WORLD, request[3]);


        //利用通信的时间计算矩阵中间值
        int begin_row = 0==myid ? 2 : 1;
        int end_row = 3==myid ? (SIZE-1) : (SIZE);
        for (row = begin_row; row < end_row; row++)
            for (col = 1; col < N-1; col++)
                matrix2[row][col] = 0.25 * (matrix1[row][col-1] + matrix1[row][col+1] + matrix1[row+1][col] + matrix1[row-1][col]);


        //利用通信的时间更新矩阵
        for(row = begin_row; row <= end_row; row++)
            for(col = 1; col < N-1; col++)
                matrix1[row][col] = matrix2[row][col];
        MPI_Waitall(4, &request[0], &status[0]);
    }
    MPI_Barrier(MPI_COMM_WORLD);
    MPI_Finalize();
    return 0;
}

       如果一个通信会被重复执行 比如循环结构内的通信调用 MPI提供了特殊的实现方式 对这样的通信进行优化 以降低不必要的通信开销 它将通信参数和MPI的内部对象建立固 定的联系 然后通过该对象完成重复通信的任务 。大致步骤如下
      1 通信的初始化 比如MPI_SEND_INIT       
      2 启动通信 MPI_START       
      3 完成通信 MPI_WAIT       
      4 释放查询对象 MPI_REQUEST_FREE

#include<mpi.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 8;
const int SIZE = N / 4;
const int T = 2;

int main()
{
    double matrix1[SIZE+2][N], matrix[SIZE+2][N];
    int myid;
    MPI_Status status[4];
    MPI_Request request[4];

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);

    memset(matrix1, 0, sizeof matrix1);
    memset(matrix2, 0, sizeof matrix2);

    //赋值边界数据
    if(0 == myid)
        for(int j = 0; j < N; j++)
            matrix1[1][j] = matrix[2][j] = N;
    if(3 == myid)
        for(int j = 0; j < N; j++)
            matrix1[SIZE][j] = matrix2[SIZE][j] = N;
    for(int i = 1; i < SIZE+1; i++)
        matrix1[i][0] = matrix1[i][N-1] = matrix2[0] = matrix2[N-1] = N;
    //引入虚拟进程简化代码
    int up_proc_id = myid==0 ? MPI_PROC_NULL : myid - 1;
    int down_proc_id = myid==3 ? MPI_PROC_NULL : myid + 1;
    //初始化重复非阻塞通信
    int tag1 = 1, tag2 = 2;
    MPI_Send_init(&matrix2[1][0], N, MPI_DOUBLE, up_proc_id, tag1, MPI_COMM_WORLD, request[0]);
    MPI_Send_init(&matrix2[SIZE][0], N, MPI_DOUBLE, down_proc_id, tag2, MPI_COMM_WORLD, request[1]);
    MPI_Recv_init(&matrix1[SIZE+1][0], N, MPI_DOUBLE, down_proc_id, tag1, MPI_COMM_WORLD, request[2]);
    MPI_Recv_init(&matrix1[0][0], N, MPI_DOUBLE, up_proc_id, tag1, MPI_COMM_WORLD, request[3]);
    //jacobi迭代
    int t, row, col;
    for(t = 0; t < T; t++)
    {
        if(0 == myid)
            for(col = 1; col < N-1; col++)
                matrix2[SIZE][col] = 0.25 * (matrix1[SIZE][col-1] + matrix1[SIZE][col+1] + matrix1[SIZE-1][col] + matrix[SIZE+1][col]);
        else if(3 == myid)
            for(col = 1; col < N-1; col++)
                matrix2[1][col] = 0.25 * (matrix1[1][col-1] + matrix1[1][col+1] + matrix1[0][col] + matrix1[2][col]);;
        else
            for(col = 1; col < N-1; col++) // 中间的矩阵块
                matrix2[SIZE][col] = 0.25 * (matrix1[SIZE][col-1] + matrix1[SIZE][col+1] + matrix1[SIZE+1][col] + matrix1[SIZE-1][col]);
                matrix2[1][col] = 0.25 * (matrix1[1][col-1] + matrix1[1][col+1] + matrix1[2][col] + matrix1[0][col]);
        //启动非阻塞通信传递边界数据
        MPI_Startall(4, &request[0]);

        //利用通信的时间计算矩阵中间值
        int begin_row = 0==myid ? 2 : 1;
        int end_row = 3==myid ? (SIZE-1) : (SIZE);
        for (row = begin_row; row < end_row; row++)
            for (col = 1; col < N-1; col++)
                matrix2[row][col] = 0.25 * (matrix1[row][col-1] + matrix1[row][col+1] + matrix1[row+1][col] + matrix1[row-1][col]);

        //利用通信的时间更新矩阵
        for(row = begin_row; row <= end_row; row++)
            for(col = 1; col < N-1; col++)
                matrix1[row][col] = matrix2[row][col];
        MPI_Waitall(4, &request[0], &status[0]);
    }
    //释放非阻塞通信对象
    for(int i = 0; i < 4; i++) MPI_Request_free(&request[i]);
    MPI_Barrier(MPI_COMM_WORLD);
    MPI_Finalize();
    return 0;
}




评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值