C++11 并行化:犰狳的 set_seed_random() 中的瓶颈

Posted

技术标签:

【中文标题】C++11 并行化:犰狳的 set_seed_random() 中的瓶颈【英文标题】:C++11 parallelization: bottleneck in Armadillo's set_seed_random() 【发布时间】:2018-11-08 14:19:23 【问题描述】:

在 C++11 中,arma_rng::set_seed_random() 的使用会产生瓶颈。我展示了一种重现它的方法。

考虑这个简单的代码:

#include <armadillo>    // Load Armadillo library.
using namespace arma;

int main()

bool jj = true;
while ( jj == true )
    arma_rng::set_seed_random();            // Set the seed to generate random numbers.
    double rnd_number = randu<double>();    // Generate a random number.



我用它编译过

g++ -std=c++11 -Wall -g bayesian_estimation.cpp -o bayesian_estimation -O2 -larmadillo

当我在终端中运行可执行文件时,我看到其中一个内核正在以接近 100% 的 CPU% 处理它。如果我运行它的更多实例,每个相应进程的 CPU% 会减少,但不会使用新的(和空闲的!)内核。我在this question中详细说明了这种行为。

为什么会这样?

【问题讨论】:

【参考方案1】:

我假设 Armadillo 从操作系统维护的真实随机数池中获取 set_seed_random() 的种子(例如,大多数 *NIX 操作系统上的 /dev/random)。由于这需要熵的物理源(通常,使用击键的时间、网络事件、其他中断源),所以这个池是有限的,并且可以比生成新的随机数更快地耗尽。

在您的情况下,我假设一个全速运行的可执行文件以与添加新熵大致相同的速度耗尽池。一旦您添加第二个、第三个......,它们就会在等待新的随机数进入池时停止。

【讨论】:

有道理。有没有一种简单的方法可以知道该池有多大以及填满的频率? 我不知道“官方”的方式,但粗略估计,您也许可以运行 'dd if=/dev/random of=tmpfile' 一分钟,看看你有多少数据得到。【参考方案2】:

查看伪随机数生成器的代码,您会发现实例化它和/或给它一个新种子可能是一个相当昂贵的过程。您通常应该只为每个线程实例化/播种 一个 并在线程的剩余生命周期中使用它。

#include <armadillo>    // Load Armadillo library.
using namespace arma;

int main()

    bool jj = true;
    arma_rng::set_seed_random();            // Set the seed to generate random numbers.

    while ( jj == true )
        double rnd_number = randu<double>();    // Generate a random number.
        

除非定义了ARMA_USE_CXX11,否则arma_rng::set_seed_random() 似乎使用了多种备用方法。我的猜测是尝试/dev/urandom 时会很幸运。请man urandom 了解更多信息。

【讨论】:

以上是关于C++11 并行化:犰狳的 set_seed_random() 中的瓶颈的主要内容,如果未能解决你的问题,请参考以下文章

C++ Armadillo 和 OpenMp:外积求和的并行化 - 定义 Armadillo 矩阵的约简

C++中犰狳矩阵维度的动态参数化

C++ 犰狳库提供了对 `arma::arma_rng_cxx11_instance' 的未定义引用

在简单的逐行计算任务中,为啥犰狳与 C 风格的数组相比如此缓慢

ubuntu中的犰狳问题

如何从 C++(带有犰狳)代码链接到 PETSc?