C++ 并行计算 MPI Tutorial-4

本文介绍了一个使用 C++ 和 MPI 进行并行处理的随机游走问题。通过点对点通讯,将域划分并初始化 Walker,在多个进程中处理 Walker 的移动。讨论了可能导致死锁的情况及预防措施,以及如何确认所有 Walker 完成。此外,还探讨了随机游走与并行粒子跟踪的相似性。
摘要由CSDN通过智能技术生成


点对点通讯应用-随机游走问题描述

问题的基本定义如下,给定一个 Min, Max, 和随机游走器 W,使得 W 在往右走 S 步。如果超出范围,则会重新回到起点。W 每次只能移动一个单位。


让我们概述一下如何并行处理随机游走。

与许多并行处理程序一样,第一项相关任务是在各个进程之间划分域。随机游走问题具有大小为 Max - Min + 1 的一维域。假设 Walker 只能走整数大小的步数,我们可以轻松地在整个过程中将域划分为几乎相等的块。

例如,如果 Min 为 0,Max 为 20,我们有 4 个进程,我们可以进行如下域划分。


前三个进程每个进程拥有域的 5 个单元,最后一个进程占用 6 个单元。一旦对域进行了划分,应用程序将初始化 Walker 。

例如,进程 0 进行 6 步游走,执行步骤如下:

  1. Walker 开始采取增量步骤。但是当其达到值 4 时,它已到达进程 0 的边界的尽头。现在,进程 0 必须跟进程 1 进行通讯。
  2. 进程 1 接收 Walker ,并继续行走达到总步数 6 。然后 Walker 可以继续进行新的随机游走。

如果步长更长, Walker 有可能经过更多进程。

编码解决

首先我们确定程序的基本特征:

  • 每个进程处理域的一部分
  • 每个进程初始化 N 次 Walker ,每次遍历在本地域的第一个值开始
  • 每个 Walker 有两个相关整数值,当前 Walker 的位置以及剩余要走的步数
  • Walker 遍历该域,并传递到下一个进程,直到完成游走
  • 当所有 Walker 都完成时,所有进程终止

首先我们编写域分解的代码,该函数将考虑域的总大小并未 MPI 进程找到合适的子域,并将域的其余部分交给最终进程。为了简便,我们调用 MPI_Abort 处理任何发现的错误。

void decompose_domain(int domain_size, int world_rank,
                      int world_size, int* subdomain_start,
                      int* subdomain_size) {
   
    if (world_size > domain_size) {
   
    	// 不关心此特例,假设域的大小一点过大于通讯组规模
        MPI_Abort(MPI_COMM_WORLD, 1);
    }
    *subdomain_start = domain_size / world_size * world_rank;
    *subdomain_size = domain_size / world_size;
    if (world_rank == world_size - 1) {
   
        // 多余部分交给最后一个进程处理
        *subdomain_size += domain_size % world_size;
    }
  }

该函数返回一个子域开始地址以及子域大小。

我们定义一个 Walker 结构:

typedef struct {
   
    int location;
    int num_steps_left_in_walk;
} Walker;

定义初始化 Walker 函数,接受子域边界并添加游走器进入 incoming_walkers 向量中。

void initialize_walkers(int num_walkers_per_proc, int max_walk_size,
                        int subdomain_start, int subdomain_size,
                        vector<Walker>* incoming_walkers) {
   
    Walker walker;
    for (int i = 0; i < num_walkers_per_proc; i++) {
   
        // 在子域中初始化 Walker 
        walker.location = subdomain_start;
        walker.num_steps_left_in_walk =
            (rand() / (float)RAND_MAX) * max_walk_size;
        incoming_walkers->push_back(walker);
    }
}

初始化之后就该使得 Walker 前进了,我们构造一个函数负责行走功能,并将超出本地范围内的步行器加入到 outgoing_walkers 向量中。

void walk(Walker*
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值