c++超快的线程安全rand函数

C++ super fast thread-safe rand function

本文关键字:安全 rand 函数 线程 c++      更新时间:2023-10-16
void NetClass::Modulate(vector <synapse> & synapses )
{
    int size = synapses.size();
    int split = 200 * 0.5;
    for(int w=0; w < size; w++)
        if(synapses[w].active)
            synapses[w].rmod = ((rand_r(seedp) % 200 - split ) / 1000.0);
}

函数rand_r(seedp)严重阻碍了我的程序。具体来说,当串行运行时,它使我的速度降低了3倍,在16核上运行时降低了4.4倍。rand()不是一个选择,因为它更糟糕。我能做些什么来简化这件事吗?如果它会产生影响,我认为我可以承受统计随机性方面的损失。预生成(在执行之前)一个随机数列表,然后加载到线程堆栈是一个选项吗?

问题是seedp变量(及其内存位置)在几个线程之间共享。处理器内核每次访问这个不断变化的值时都必须同步它们的缓存,这会影响性能。解决方案是所有线程都使用自己的seedp,从而避免缓存同步。

这取决于需要的统计随机性有多好。对于高质量,梅森扭扭机,或其SIMD变体,是一个很好的选择。您可以一次生成和缓冲一大块伪随机数,并且每个线程都可以有自己的状态向量。Park-Miller-Carta PRNG非常简单——这些家伙甚至把它实现为CUDA内核。

Marsaglia的xor-shift生成器可能是您可以使用的最快的"合理质量"生成器。它不完全具有与MT19937或WELL相同的"质量",但老实说,这些差异是学术上的诡辩。对于所有真实的、实际的应用,除了在执行速度上有1-2个数量级的差异,在内存消耗上有3个数量级的差异之外,没有可观察到的差异。

xor-shift生成器也是自然线程安全的(在某种意义上,它将产生非确定性的、伪随机的结果,并且它不会崩溃),没有任何特殊的东西,并且在另一种意义上(在某种意义上,它将生成每个线程独立的、确定性的、伪随机的数字),通过每个线程一个实例,它可以简单地使线程安全。
使用原子比较交换也可以使它在另一种意义上是线程安全的(生成一个确定性的、伪随机的序列,分发给线程),但我认为这不是很有用。

xor-shift生成器唯一值得注意的三个问题是:

  • 对于623维,它不是k分布的,但老实说,谁在乎呢。我不能考虑超过4个维度(甚至这是一个谎言!),也无法想象有多少应用程序需要超过10或20个维度。这必须是一些相当深奥的模拟。
  • 它通过了大多数,但从来没有迂腐的统计检验。再说一遍,谁在乎呢。大多数人使用的随机生成器甚至没有通过单一测试,也从未注意到。
  • 零种子将产生一个零序列。这可以通过向其中一个临时变量添加一个非零常数来简单地修复(我想知道为什么Marsaglia从未想到过这一点?)话虽如此,MT19937在零种子的情况下也表现得非常糟糕,并且几乎无法恢复。

看看Boost: http://www.boost.org/doc/libs/1_47_0/doc/html/boost_random.html它有许多不同复杂度(=速度)和随机性(周期长度)的选项。

如果你不需要最大的随机性,你可以用一个简单的Mersenne Twister。

你绝对需要有一个共享的随机吗?

我有一个类似的争用问题前一段时间,最适合我的解决方案是为每个线程创建一个新的随机类(我在c#中工作)。反正也很便宜。

如果你正确地播种它们,以确保你不会产生重复的种子,你应该没事。这样你就不会有共享状态,所以你不需要使用threadsafe函数。

问候GJ

也许你不必在每次迭代中调用它?您可以初始化一个预先随机化的元素数组,并连续使用它…

我认为你可以像这样使用OpenMP进行并行:

#pragma omp parallel
for(int w=0; w < size; w++)