c++超快的线程安全rand函数
C++ super fast thread-safe rand function
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++)
- 从不同线程使用int64的不同字节安全吗
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 虚拟决赛作为安全
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何将元素添加到数组的线程安全函数?
- C++中的线程安全删除
- 通过网络、跨平台传递std::变体是否安全
- 为什么我不能将 rand() 与数组的大小一起使用?
- 在std::thread中,joinable()然后join()线程安全吗
- 使用std::istream::peek()总是安全的吗
- 从值小于256的uint16到uint8的Endian安全转换
- 为什么新的随机库比std::rand()更好
- 在c++队列中使用pop和visit实现线程安全
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 全局变量 多读取器 一个写入器多线程安全?
- 安全到标准:移动会员?
- AcquireCredentialsHandleA() 返回 PFX 文件的0x8009030e(安全包中没有可用的凭据
- 线程安全的并行RNG比顺序rand()慢
- c++超快的线程安全rand函数