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

时间:2011-11-27 10:57:03

标签: c++ multithreading optimization random

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()不是一种选择,因为它更糟糕。有什么我可以做的来简化这个吗?如果它会产生影响,我认为我可以在统计随机性方面遭受损失。预先生成(在执行之前)一个随机数列表,然后加载到线程堆栈是一个选项吗?

7 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:4)

这取决于统计随机性需要多好。对于高质量,Mersenne twister或其SIMD变体是一个不错的选择。您可以一次生成并缓冲大块伪随机数,每个线程都可以拥有自己的状态向量。 Park-Miller-Carta PRNG非常简单 - these guys甚至将其作为CUDA内核实现。

答案 2 :(得分:4)

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

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

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

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

答案 3 :(得分:2)

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

如果您不需要最大的随机性,您可能会使用简单的Mersenne Twister。

答案 4 :(得分:1)

你绝对需要1个共享随机?

前一段时间我有类似的争用问题,对我来说最有效的解决方案是为每个线程创建一个新的Random类(我在C#中工作)。无论如何,它们都很便宜。

如果你正确播种它们以确保你不创造重复的种子你应该没事。那么你就不会有共享状态,因此你不需要使用线程安全函数。

关心GJ

答案 5 :(得分:0)

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

答案 6 :(得分:-5)

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

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