Pregunta Generador de números aleatorios que solo genera un número aleatorio


Tengo la siguiente función:

//Function to get random number
public static int RandomNumber(int min, int max)
{
    Random random = new Random();
    return random.Next(min, max);
}

Cómo lo llamo:

byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
    mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);

Si paso ese ciclo con el depurador durante el tiempo de ejecución, obtengo valores diferentes (que es lo que quiero). Sin embargo, si pongo un punto de corte dos líneas debajo de ese código, todos los miembros de la matriz "mac" tienen el mismo valor.

¿Por qué sucede eso?


647
2018-04-20 12:11


origen


Respuestas:


Cada vez que lo haces new Random() se inicializa usando el reloj. Esto significa que, en un ciclo cerrado, obtienes el mismo valor muchas veces. Debes mantener un solo Random instancia y seguir usando Next sobre el mismo ejemplo.

//Function to get a random number 
private static readonly Random random = new Random(); 
private static readonly object syncLock = new object(); 
public static int RandomNumber(int min, int max)
{
    lock(syncLock) { // synchronize
        return random.Next(min, max);
    }
}

Editar (ver comentarios): ¿por qué necesitamos un lock ¿aquí?

Básicamente, Next va a cambiar el estado interno de la Random ejemplo. Si hacemos eso al mismo tiempo desde múltiples hilos, podría argumentan "acabamos de hacer que el resultado sea aún más aleatorio", pero lo que somos actualmente hacer es potencialmente romper la implementación interna, y también podríamos comenzar a obtener los mismos números de diferentes hilos, que podría ser un problema, y ​​puede que no. Sin embargo, la garantía de lo que sucede internamente es el problema mayor; ya que Random hace no hacer cualquier garantía de seguridad hilo. Por lo tanto, hay dos enfoques válidos:

  • sincronizar para que no accedamos al mismo tiempo desde diferentes hilos
  • usar diferente Random instancias por hilo

Cualquiera puede estar bien; pero mutexing una soltero ejemplo de varios llamantes al mismo tiempo es solo pedir problemas.

los lock logra el primero (y más simple) de estos enfoques; Sin embargo, otro enfoque podría ser:

private static readonly ThreadLocal<Random> appRandom
     = new ThreadLocal<Random>(() => new Random());

esto es por subproceso, por lo que no necesita sincronizar.


885
2018-04-20 12:12



Para facilitar su reutilización en toda su aplicación, una clase estática puede ayudar.

public static class StaticRandom
{
    private static int seed;

    private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
        (() => new Random(Interlocked.Increment(ref seed)));

    static StaticRandom()
    {
        seed = Environment.TickCount;
    }

    public static Random Instance { get { return threadLocal.Value; } }
}

Puede usar luego usar instancia aleatoria estática con código tal como

StaticRandom.Instance.Next(1, 100);

94
2017-07-13 15:25



La solución de Mark puede ser bastante costosa ya que necesita sincronizarse cada vez.

Podemos solucionar la necesidad de sincronización utilizando el patrón de almacenamiento específico de subprocesos:


public class RandomNumber : IRandomNumber
{
    private static readonly Random Global = new Random();
    [ThreadStatic] private static Random _local;

    public int Next(int max)
    {
        var localBuffer = _local;
        if (localBuffer == null) 
        {
            int seed;
            lock(Global) seed = Global.Next();
            localBuffer = new Random(seed);
            _local = localBuffer;
        }
        return localBuffer.Next(max);
    }
}

Mida las dos implementaciones y debería ver una diferencia significativa.


49
2018-06-23 11:26



Mi respuesta de aquí:

Solo reiterando la solución correcta:

namespace mySpace
{
    public static class Util
    {
        private static rnd = new Random();
        public static int GetRandom()
        {
            return rnd.Next();
        }
    }
}

Entonces puedes llamar:

var i = Util.GetRandom();

todo a través de.

Si necesita estrictamente un verdadero método estático sin estado para generar números aleatorios, puede confiar en un Guid.

public static class Util
{
    public static int GetRandom()
    {
        return Guid.NewGuid().GetHashCode();
    }
}

Va a ser un poquito más lento, pero puede ser mucho más aleatorio que Random.Next, Por lo menos desde mi experiencia.

Pero no:

new Random(Guid.NewGuid().GetHashCode()).Next();

La creación de objetos innecesarios lo hará más lento, especialmente debajo de un bucle.

Y Nunca:

new Random().Next();

No solo es más lento (dentro de un bucle), su aleatoriedad es ... bueno, no muy bueno según yo ...


30
2018-03-31 12:34



Prefiero usar la siguiente clase para generar números aleatorios:

byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider prov = new System.Security.Cryptography.RNGCryptoServiceProvider();
prov.GetBytes(random);

21
2018-04-20 12:25



1) Como dijo Marc Gravell, intenta usar UN generador aleatorio. Siempre es genial agregar esto al constructor: System.Environment.TickCount.

2) Un consejo. Digamos que desea crear 100 objetos y suponga que cada uno de ellos debe tener su propio generador aleatorio (útil si calcula CARGAS de números aleatorios en un período de tiempo muy corto). Si hicieras esto en un bucle (generación de 100 objetos), podrías hacerlo así (para asegurar la aleatoriedad total):

int inMyRandSeed;

for(int i=0;i<100;i++)
{
   inMyRandSeed = System.Environment.TickCount + i;
   .
   .
   .
   myNewObject = new MyNewObject(inMyRandSeed);  
   .
   .
   .
}

// Usage: Random m_rndGen = new Random(inMyRandSeed);

Aclamaciones.


12



Hay muchas soluciones, aquí una: si solo quiere borrar números, las letras y el método reciben un resultado aleatorio y la longitud del resultado.

public String GenerateRandom(Random oRandom, int iLongitudPin)
{
    String sCharacters = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
    int iLength = sCharacters.Length;
    char cCharacter;
    int iLongitudNuevaCadena = iLongitudPin; 
    String sRandomResult = "";
    for (int i = 0; i < iLongitudNuevaCadena; i++)
    {
        cCharacter = sCharacters[oRandom.Next(iLength)];
        sRandomResult += cCharacter.ToString();
    }
    return (sRandomResult);
}

1