作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要一个线程安全的高性能随机数生成器。我只需要值类型(目前为ulong
)中的随机字节,而不是范围内的字节。我使用了C#内置的Random
类,但是它有点慢,而且不是线程安全的。
后来我移到了XORShift函数,该函数实际上工作得很好,但是要实现线程安全,我需要将计算放在lock
中,这会严重降低性能。
我用来生成随机ulong
的内容如下:
public class Rand
{
ulong seed = 0;
object lockObj = new object();
public Rand()
{
unchecked
{
seed = (ulong)DateTime.Now.Ticks;
}
}
public Rand(ulong seed)
{
this.seed = seed;
}
public ulong GetULong()
{
unchecked
{
lock (lockObj)
{
ulong t = 0;
t = seed;
t ^= t >> 12;
t ^= t << 25;
t ^= t >> 27;
seed = t;
return t * 0x2545F4914F6CDD1D;
}
}
}
}
这可以正常且快速地工作,但是如果从200个并发线程中调用它,则锁定大约需要
1-2us
,否则计算将在
100ns
下完成。
ulong t
声明并直接在种子上工作,那么几乎没有机会为两个并发调用生成相同的随机数,但是也有可能该值会从值范围移出,例如
t << 25
将被不同的线程连续调用多次,而不进行旋转,它将变成简单的0。
最佳答案
您可以在不锁定的情况下做到这一点,并且仍然是线程安全的。假设计算非常快,并且执行速度较慢,那么在开始计算和完成计算之间,如果另一个线程对其进行了更改,则简单地重新计算可能会更快。您可以使用Interlocked.CompareExchange
自旋循环来做到这一点。唯一的困难是没有超长版本,因此我们必须使用不安全的方法来获得等效版本。
private static unsafe ulong InterlockedCompareExchange(ref ulong location,
ulong value, ulong comparand)
{
fixed (ulong* ptr = &location)
{
return (ulong)Interlocked.CompareExchange(ref *(long*)ptr, (long)value, (long)comparand);
}
}
public ulong GetULong()
{
unchecked
{
ulong prev = seed;
ulong t = prev;
t ^= t >> 12;
t ^= t << 25;
t ^= t >> 27;
while (InterlockedCompareExchange(ref seed, t, prev) != prev)
{
prev = seed;
t = prev;
t ^= t >> 12;
t ^= t << 25;
t ^= t >> 27;
}
return t * 0x2545F4914F6CDD1D;
}
}
关于c# - 线程安全的高性能随机数发生器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64937914/
我是一名优秀的程序员,十分优秀!