我需要在多个正在运行的线程中快速生成随机浮点数。我试过使用System.Random
,但它对我的需求来说太慢了,它会在多个线程中返回相同的数字。 (当我运行我在单线程应用程序,它工作正常。)另外,我需要确保生成的数字是0和100之间用于C#的快速线程安全随机数生成器
这里是我现在想:
number = random.NextDouble() * 100;
我应该试试什么?
我需要在多个正在运行的线程中快速生成随机浮点数。我试过使用System.Random
,但它对我的需求来说太慢了,它会在多个线程中返回相同的数字。 (当我运行我在单线程应用程序,它工作正常。)另外,我需要确保生成的数字是0和100之间用于C#的快速线程安全随机数生成器
这里是我现在想:
number = random.NextDouble() * 100;
我应该试试什么?
这是我对其采取(需要.NET 4.0):
public static class RandomGenerator
{
private static object locker = new object();
private static Random seedGenerator = new Random(Environment.TickCount);
public static double GetRandomNumber()
{
int seed;
lock (locker)
{
seed = seedGenerator.Next(int.MinValue, int.MaxValue);
}
var random = new Random(seed);
return random.NextDouble();
}
}
和测试,以检查1000次迭代的每个值是唯一的:
[TestFixture]
public class RandomGeneratorTests
{
[Test]
public void GetRandomNumber()
{
var collection = new BlockingCollection<double>();
Parallel.ForEach(Enumerable.Range(0, 1000), i =>
{
var random = RandomGenerator.GetRandomNumber();
collection.Add(random);
});
CollectionAssert.AllItemsAreUnique(collection);
}
}
我不能保证它永远不会返回重复值,但我已经运行10000次迭代的测试,并通过了测试。
如果Random
给了你相同的数字,那么你可能会错误地使用它,要么通过紧密连续创建多个实例(意味着它们将使用相同的种子并因此生成相同的序列),要么在多个线程中使用单个实例(从而“打破”该实例,因为多线程使用并不安全)。
如果速度和Random
随机性在单个线程中运行时,都不够好,那么你可以尝试在ThreadLocal<T>
包装,以确保在你的多线程的情况下为每个线程单独的实例:
var number = _rng.Value.NextDouble() * 100;
// ...
private static int _staticSeed = Environment.TickCount;
private static readonly ThreadLocal<Random> _rng = new ThreadLocal<Random>(() =>
{
int seed = Interlocked.Increment(ref _staticSeed) & 0x7FFFFFFF;
return new Random(seed);
});
我使用windows cryptoAPI获得很好的随机数。为了提高性能,我会为一个8KB的随机数据块进行一次调用,并从中分配数字,而不是为每个数字调用cryptoAPI。与正常随机数相比,不知道最终的表现如何。但随机化要好得多(请查看Windows CryptoAPI上的详细信息)
这是代码;
// UNIT RandomNumberGeneratorBase
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FastLibrary
{
public abstract class RandomNumberGeneratorBase
{
private int _byteBufSize;
private byte[] _buf;
private int _idx;
private int _lastsize;
public RandomNumberGeneratorBase(int bufSize = 8092)
{
_byteBufSize = bufSize;
_buf = new byte[_byteBufSize];
_idx = _byteBufSize;
}
protected abstract void GetNewBuf(byte[] buf);
private void CheckBuf(int bytesFreeNeeded = 1)
{
_idx += _lastsize;
_lastsize = bytesFreeNeeded;
if (_idx + bytesFreeNeeded < _byteBufSize) { return; }
GetNewBuf(_buf);
_idx = 0;
_lastsize = 0;
}
public byte GetRandomByteStartAtZero(int belowValue)
{
return (byte)(Math.Round(((double)GetRandomByte() * (belowValue - 1))/255));
}
public int GetRandomIntStartAtZero(int belowValue)
{
return (int)(Math.Round(((double)GetRandomUInt32() * (double)(belowValue - 1))/(double)uint.MaxValue));
}
public byte GetRandomByte()
{
CheckBuf();
return _buf[_idx];
}
public bool GetRandomBool()
{
CheckBuf();
return _buf[_idx] > 127;
}
public ulong GetRandomULong()
{
CheckBuf(sizeof(ulong));
return BitConverter.ToUInt64(_buf, _idx);
}
public int GetRandomInt()
{
CheckBuf(sizeof(int));
return BitConverter.ToInt32(_buf, _idx);
}
/// <summary>
/// Double from 0 to 1 (might be zero, will never be 1)
/// </summary>
public double GetRandomDouble()
{
return GetRandomUInt32()/(1d + UInt32.MaxValue);
}
/// <summary>
/// Float from 0 to 1 (might be zero, will never be 1)
/// </summary>
public float GetRandomFloat()
{
return GetRandomUInt32()/(1f + UInt32.MaxValue);
}
public uint GetRandomUInt32()
{
CheckBuf(sizeof(UInt32));
return BitConverter.ToUInt32(_buf, _idx);
}
}
}
// UNIT StrongRandomNumberGenerator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace FastLibrary
{
public sealed class StrongRandomNumberGenerator : RandomNumberGeneratorBase
{
private RNGCryptoServiceProvider _rnd;
public StrongRandomNumberGenerator()
{
_rnd = new RNGCryptoServiceProvider();
}
protected override void GetNewBuf(byte[] buf)
{
_rnd.GetBytes(buf);
}
}
}
如果随机给出的数字始终相同,那么您很可能没有正确使用它。还要注意'Random'不是线程安全的。 – dasblinkenlight 2012-02-16 11:05:12
另请注意,生成真正的随机数是一件大事:http://www.random.org/randomness/ – 2012-02-16 11:13:03
非常快速和线程安全:'返回4;' – 2012-02-16 11:15:24