C++超快速线程安全rand功能

Mat*_*son 12 c++ random optimization multithreading

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);
}
Run Code Online (Sandbox Code Playgroud)

该功能rand_r(seedp)严重瓶颈我的计划.具体来说,它在串行运行时减慢了3倍,在16核运行时减慢了4.4倍.rand()不是一种选择,因为它更糟糕.有什么我可以做的来简化这个吗?如果它会产生影响,我认为我可以在统计随机性方面遭受损失.预先生成(在执行之前)一个随机数列表,然后加载到线程堆栈是一个选项吗?

Bre*_*ale 5

这取决于统计随机性需要有多好。对于高质量,梅森捻线机或其 SIMD 变体是一个不错的选择。您可以一次生成和缓冲一大块伪随机数,并且每个线程都可以有自己的状态向量。该公园-米勒-宪章PRNG是非常简单的-这些家伙甚至实现了它作为CUDA内核。

  • Park-Miller-Carta 如何比 rand_r 更快?您的代码中的“seedp”是否有可能在所有线程之间共享?在这种情况下,内核必须同步它们的缓存才能访问相同的内存位置,这需要时间。给每个线程自己的“seedp”,看看会发生什么。 (3认同)

Dam*_*mon 5

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

异或移位生成器自然也是线程安全的(从某种意义上说,它将产生非确定性的伪随机结果,并且不会崩溃),没有任何特别之处,并且可以在另一种意义上轻松地使其成为线程安全的(在通过每个线程有一个实例,它将生成每个线程独立的、确定性的、伪随机数的感觉。
也可以使用原子比较交换在另一种意义上使它成为线程安全的(生成一个确定性的伪随机序列,并在线程到来时分发给它们),但我认为这不是很有用。

异或移位生成器仅有的三个值得注意的问题是:

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


Dia*_*cus 5

问题是seedp变量(及其内存位置)在多个线程之间共享.处理器核心必须在每次访问这些不断变化的值时同步其缓存,这会妨碍性能.解决方案是所有线程都使用自己的线程seedp,因此避免缓存同步.