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);
}
Como 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 bucle con el depurador durante el tiempo de ejecución obtengo valores diferentes (que es lo que quiero). Sin embargo, si pongo un punto de interrupción dos líneas debajo de ese código, todos los miembros de la mac
matriz tienen el mismo valor.
¿Por qué sucede eso?
new Random().Next((int)0xFFFF, (int)0xFFFFFF) % 256);
no produce mejores números "aleatorios" que.Next(0, 256)
Rand.Next(int, int)
método estático que proporciona acceso estático a valores aleatorios sin bloquear o encontrarse con el problema de reutilización de semillasRespuestas:
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. Debe mantener una única instancia aleatoria y seguir usando Siguiente en la misma instancia.Editar (ver comentarios): ¿por qué necesitamos un
lock
aquí?Básicamente,
Next
va a cambiar el estado interno de laRandom
instancia. Si hacemos eso al mismo tiempo desde múltiples hilos, podría argumentar "acabamos de hacer que el resultado sea aún más aleatorio", pero lo que realmente estamos haciendo es potencialmente romper la implementación interna, y también podríamos comenzar a obtener los mismos números de diferentes hilos, lo que podría ser un problema, y podría no serlo. Sin embargo, la garantía de lo que sucede internamente es el problema más importante; yaRandom
que no garantiza la seguridad del hilo. Por lo tanto, hay dos enfoques válidos:Random
instancias por hiloCualquiera puede estar bien; pero eliminar una sola instancia de varias personas que llaman al mismo tiempo solo es un problema.
El
lock
logra el primero (y más simple) de estos enfoques; Sin embargo, otro enfoque podría ser:esto es por subproceso, por lo que no necesita sincronizar.
fuente
lock (syncObject)
lo tanto , solo ayudará si todas lasrandom.Next()
llamadas también están dentrolock (syncObject)
. Si el escenario que describe ocurre incluso con ellock
uso correcto , también es muy probable que ocurra en un escenario de subproceso único (por ejemplo,Random
está sutilmente roto).Para facilitar la reutilización en toda la aplicación, una clase estática puede ayudar.
Puede usar y luego usar una instancia aleatoria estática con código como
fuente
La solución de Mark puede ser bastante costosa ya que necesita sincronizarse cada vez.
Podemos evitar la necesidad de sincronización utilizando el patrón de almacenamiento específico de subproceso:
Mida las dos implementaciones y debería ver una diferencia significativa.
fuente
Random
instancia global adicional para obtener la semilla es una buena idea. Tenga en cuenta también que el código puede simplificarse aún más utilizando laThreadLocal<T>
clase introducida en .NET 4 (como Phil también escribió a continuación ).Mi respuesta desde aquí :
Solo reiterando la solución correcta :
Entonces puedes llamar:
todo a través de.
Si necesita estrictamente un método estático sin estado verdadero para generar números aleatorios, puede confiar en a
Guid
.Va a ser un poco más lento, pero puede ser mucho más aleatorio que
Random.Next
, al menos desde mi experiencia.Pero no :
La creación innecesaria de objetos lo hará más lento, especialmente bajo un bucle.
Y nunca más :
No solo es más lento (dentro de un bucle), su aleatoriedad es ... bueno, no es realmente bueno según yo ...
fuente
Random
clase coincide con el caso 2 (por lo tanto, el caso 1 también). Sólo se puede reemplazar el uso deRandom
por suGuid+Hash
si está no en el caso 2. Caso 1 es probablemente suficiente para responder a la pregunta, y luego, suGuid+Hash
fina obras. Pero no se dice claramente (ps: este uniforme )Random
y aGuid.NewGuid().GetHashCode()
través de Ent ( fourmilab.ch/random ) y ambos son igualmente aleatorios.new Random(Guid.NewGuid().GetHashCode())
funciona igual de bien, al igual que el uso de un "maestro" sincronizadoRandom
para generar semillas para "hijos"Random
. Por supuesto, depende de cómo su sistema genera Guías: para mi sistema, son bastante aleatorias, y en otras puede incluso ser criptoaleatorio. Entonces, Windows o MS SQL parece estar bien hoy en día. Sin embargo, Mono y / o móvil pueden ser diferentes.GetHashCode
el Guid en .NET se deriva de su representación de cadena. La salida es bastante aleatoria para mi gusto.Preferiría usar la siguiente clase para generar números aleatorios:
fuente
1) Como dijo Marc Gravell, intente usar UN generador aleatorio. Siempre es bueno 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 haría esto en un bucle (generación de 100 objetos), podría hacerlo así (para asegurar una aleatoriedad total):
Salud.
fuente
Random()
constructor predeterminado llama deRandom(Environment.TickCount)
todos modosCada vez que ejecutas
No importa si lo ejecutas millones de veces, siempre usarás la misma semilla.
Si utiliza
Obtiene una secuencia de números aleatorios diferente, si un pirata informático adivina la semilla y su algoritmo está relacionado con la seguridad de su sistema, su algoritmo está roto. Yo ejecuto mult. En este constructor, la semilla se especifica mediante el reloj del sistema y, si se crean varias instancias en un período de tiempo muy corto (milisegundos), es posible que tengan la misma semilla.
Si necesita números aleatorios seguros, debe usar la clase
Uso:
fuente
It does not matter if you execute it millions of times, you will always use the same seed.
Eso no es cierto a menos que especifique la semilla usted mismo.simplemente declare la variable de clase Random de esta manera:
si desea obtener un número aleatorio diferente cada vez de su lista, use
Cada vez declarando
Random r = new Random()
una vez.fuente
new Random()
, usa el reloj del sistema, pero si llama a ese código completo dos veces seguidas antes de que cambie el reloj, obtendrá el mismo número aleatorio. Ese es el punto principal de las respuestas anteriores.Hay muchas soluciones, aquí una: si solo desea borrar las letras y el método recibe una longitud aleatoria y el resultado.
fuente
Random
instancia, pero aún espera que la persona que llama cree una instancia compartida. Si la persona que llama crea una nueva instancia cada vez y el código se ejecuta dos veces antes de que cambie el reloj, obtendrá el mismo número aleatorio. Entonces, esta respuesta aún hace suposiciones que podrían ser erróneas.