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

C++11 parallelization: bottleneck in Armadillo's set_seed_random()

在 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% 会减少,但不会使用新的(和闲置的!)内核。我在 .

中详细说明了这种行为

为什么会这样?

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

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

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

#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_rng::set_seed_random() 使用了多种回退,除非定义了 ARMA_USE_CXX11。我的猜测是它在尝试 /dev/urandom 时会很幸运。做 man urandom 了解更多信息。