Лучший способ посеять 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];

    }
}