Лучший способ посеять Random() в singleton
У меня есть метод в одноэлементном классе, который должен использовать .NET-систему. Random()
, так как метод вызывается в многопоточной среде, я не могу создать его только один раз и объявить его статически, но я должен создавать объект Random()
каждый раз при вызове метода. Поскольку Random()
начальное значение по умолчанию основано на часах, это не является случайным в моем сенарио. Чтобы создать лучшее семя, я рассмотрел несколько методов и понял, что следующий из них является лучшим, но могут быть другие (более быстрые/лучшие) способы сделать это, о которых я хотел бы знать.
Random rnd = new Random(BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0));
Ответы
Ответ 1
Вместо того, чтобы сами пытаться найти лучшее семя, используйте System.Security.Cryptography.RandomNumberGenerator.
Он использует семя, основанное на сложном алгоритме, который включает в себя множество различных переменных среды. Системное время является одним из таких, как IIRC - MAC-адрес вашего сетевого адаптера и т.д.
Он также считается "более случайным" алгоритмом, чем тот, который реализуется классом Random.
Ответ 2
Вот моя реализация. Без резьбы без фиксации.
public static class StrongRandom
{
[ThreadStatic]
private static Random _random;
public static int Next(int inclusiveLowerBound, int inclusiveUpperBound)
{
if (_random == null)
{
var cryptoResult = new byte[4];
new RNGCryptoServiceProvider().GetBytes(cryptoResult);
int seed = BitConverter.ToInt32(cryptoResult, 0);
_random = new Random(seed);
}
// upper bound of Random.Next is exclusive
int exclusiveUpperBound = inclusiveUpperBound + 1;
return _random.Next(inclusiveLowerBound, exclusiveUpperBound);
}
}
Ответ 3
Создайте его статически и используйте блокировку, чтобы сделать ее потокобезопасной:
public static class RandomProvider {
private static Random _rnd = new Random();
private static object _sync = new object();
public static int Next() {
lock (_sync) {
return _rnd.Next();
}
}
public static int Next(int max) {
lock (_sync) {
return _rnd.Next(max);
}
}
public static int Next(int min, int max) {
lock (_sync) {
return _rnd.Next(min, max);
}
}
}
Если по какой-то причине вам по-прежнему нужен объект Random
в каждом потоке, вы можете использовать статический класс для их семени:
Random r = new Random(RandomProvider.Next() ^ Environment.TickCount);
Ответ 4
Пример программы, использующей RNGCryptoServiceProvider для генерации случайных чисел
class Program
{
public static void Main(string[] args)
{
int i;
byte bRandom;
String sL;
for (i = 0; i < 10; i++)
{
bRandom = GetRandom();
sL = string.Format("Random Number: {0}", bRandom);
Console.WriteLine(sL);
}
Console.ReadLine();
}
public static byte GetRandom()
{
RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
// Create a byte array to hold the random value.
byte[] randomNumber = new byte[1];
rngCsp.GetBytes(randomNumber);
return randomNumber[0];
}
}