c# - funcion - La mejor manera de sembrar Random() en singleton
fijar semilla en r (4)
Aquí está mi implementación. Hilo seguro sin bloqueo.
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);
}
}
Tengo un método en una clase de singleton que necesita usar el sistema .NET. Random()
, ya que el método se llama en un entorno de subprocesos múltiples, no puedo crearlo solo una vez y declararlo estáticamente, pero tengo que crear un objeto Random()
cada vez que se llama al método. Como el valor predeterminado de Random()
se basa en los tics del reloj, no es lo suficientemente aleatorio en mi senario. Para crear una mejor semilla, he examinado varios métodos y he pensado que el siguiente es el mejor, pero puede haber otras formas (más rápidas / mejores) de hacer esto que me gustaría conocer.
Random rnd = new Random(BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0));
Créelo de forma estática y usa un candado para que sea seguro para la hebra:
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);
}
}
}
Si aún necesita un objeto Random
en cada subproceso por alguna razón, puede usar la clase estática para sembrarlos:
Random r = new Random(RandomProvider.Next() ^ Environment.TickCount);
Ejemplo de programa que utiliza RNGCryptoServiceProvider para generar números aleatorios
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];
}
}
En lugar de intentar crear una mejor semilla, use System.Security.Cryptography.RandomNumberGenerator .
Utiliza una semilla basada en un algoritmo complejo que involucra muchas variables de entorno diferentes. La hora del sistema es una de esas, como es IIRC la dirección MAC de su NIC, etc.
También se considera un algoritmo ''más aleatorio'' que el implementado por la clase Random.