【问题标题】:cout slowest processor MPIcout 最慢的处理器 MPI
【发布时间】:2015-12-14 11:16:20
【问题描述】:

我正在使用 MPI 编写程序。每个处理器执行一个 for 循环:

int main(int argc, char** argv) {
  boost::mpi::environment env(argc, argv);

  for( int i=0; i<10; ++i ) {
    std::cout << "Index " << i << std::endl << std::flush;
  }
}

有没有办法让 cout 只发生在最后一个处理器上命中索引 i ?或者标记,只在最后一个处理器上执行一行?

【问题讨论】:

  • 我不知道如何让它只打印出最后一个,但获得相同效果的另一种方法是在std::cout 循环之后放置一个MPI_Barrier,并有if(rank == 0) { std::cout &lt;&lt; std::endl; } 就在障碍物之后。不过,只有在绝对必要时才这样做,因为不必要地引入同步块是确保代码不会扩展的好方法。
  • 谢谢!是的,我也想到了这个解决方案,但我真的只是想打印出一些指示代码在哪里的指标......计算工作不需要它。每次迭代都需要一段时间,而且我需要运行很多次,而且我喜欢了解自己在模拟中的距离。
  • 我不知道是否有更优雅/高效的方法,但是您能否在运行此之前将原子计数器初始化为 0,并让每个线程在完成该迭代时递增计数器?然后每个线程可以查看计数器看是否是最后一个,如果是则cout。

标签: c++ c++11 mpi cout


【解决方案1】:

这可能看起来微不足道,但实际上,对于分布式内存模型(例如 MPI)来说,您在这里提出的问题极其复杂......

在共享内存环境中,例如 OpenMP,这可以通过定义一个共享计数器轻松解决,由所有线程自动递增,然后检查它的值是否对应于线程数。如果是这样,那么这意味着所有线程都通过了该点并且当前是最后一个,他将负责打印。

在分布式环境中,定义和更新这样的共享变量非常复杂,因为每个进程都可能在远程机器上运行。为了仍然允许这一点,MPI 从 MPI-2.0 开始提出内存窗口和单向通信。然而,即使这样,也不可能在正确实现原子计数器增量的同时可靠地获得它的值。只有在 MPI 3.0 和 MPI_Fetch_and_op() 函数的引入下,这才成为可能。下面是一个实现示例:

#include <mpi.h>
#include <iostream>

int main( int argc, char *argv[] ) {

    // initialisation and inquiring of rank and size
    MPI_Init( &argc, &argv);

    int rank, size;
    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
    MPI_Comm_size( MPI_COMM_WORLD, &size );

    // creation of the "shared" counter on process of rank 0
    int *addr = 0, winSz = 0;
    if ( rank == 0 ) {
        winSz = sizeof( int );
        MPI_Alloc_mem( winSz, MPI_INFO_NULL, &addr );
        *addr = 1; // initialised to 1 since MPI_Fetch_and_op returns value *before* increment
    }
    MPI_Win win;
    MPI_Win_create( addr, winSz, sizeof( int ), MPI_INFO_NULL, MPI_COMM_WORLD, &win );

    // atomic incrementation of the counter
    int counter, one = 1;
    MPI_Win_lock( MPI_LOCK_EXCLUSIVE, 0, 0, win );
    MPI_Fetch_and_op( &one, &counter, MPI_INT, 0, 0, MPI_SUM, win );
    MPI_Win_unlock( 0, win );

    // checking the value of the counter and printing by last in time process
    if ( counter == size ) {
        std::cout << "Process #" << rank << " did the last update" << std::endl;
    }

    // cleaning up
    MPI_Win_free( &win );
    if ( rank == 0 ) {
        MPI_Free_mem( addr );
    }
    MPI_Finalize();

    return 0;
}

如您所见,对于这样一个微不足道的请求,这是相当冗长和复杂的。而且,这需要 MPI 3.0 支持。

不幸的是,在您的目标看来,Boost.MPI 仅“支持 MPI 1.1 中的大部分功能”。所以如果你真的想得到这个功能,你必须使用一些简单的 MPI 编程。

【讨论】:

  • 这个例子非常有价值,因为很难找到MPI_Fetch_and_op的简单例子。
猜你喜欢
  • 2012-03-06
  • 2021-08-23
  • 2023-03-03
  • 2012-04-16
  • 2011-08-13
  • 2013-08-09
  • 2010-11-11
  • 2015-09-25
  • 1970-01-01
相关资源
最近更新 更多