2010-07-07 17 views
5

Duplicar posibles:
System.Random keeps on returning the same valueC# Random.Next de repente deja de devolver valores aleatorios

Estoy refactorización y la expansión de un pequeño modelo de C# basado en agentes para ayudar a algunos profesores de biología predicen la propagación de una enfermedad. Cada año de la simulación, cada agente individual viaja al azar a un nodo poblacional cercano, posiblemente diseminando la enfermedad. Soy nuevo en C#, pero he leído sobre posibles problemas con Random. Luego devuelvo el mismo valor si se reinicializa con la misma hora del sistema. Para evitar esto, he creado una instancia estática a la que se hace referencia para cada nuevo valor aleatorio.

Los detalles:

En mis esfuerzos para ampliar el modelo que he cambiado para calcular la información de "viaje" para cada nodo de la población en paralelo. Al probar el modelo noté que en la nueva versión la enfermedad no se extendería más allá del primer año. La investigación adicional redujo el problema al viaje entre nodos. Después del primer año, todos los agentes permanecieron inmóviles. Examiné la función responsable de su viaje y descubrí que funciona creando una lista de todos los nodos cercanos, generando un número aleatorio < = el número de elementos en la lista, y viajando a listOfNearbyNodes [myRandomNumber].

El problema:

que luego añadió un comunicado de impresión para dar salida al valor del índice al azar para cada iteración. Descubrí que todo el modelo funciona exactamente como se esperaba para el primer año de la simulación, con los números aleatorios generados en un rango aceptable. Sin embargo, después de que termina el primer año y los bucles de simulación, el mismo código solo arrojará un índice "aleatorio" de 0. Cada hilo, cada iteración, cada nodo, cada agente, siempre 0. Como el nodo actual de un agente siempre está el primer elemento en la lista los agentes nunca se mueven de nuevo.

Pensé que esta podría ser otra manifestación del error de inicialización del sistema, así que he intentado tres formas diferentes de implementar un objeto aleatorio estático, pero no ayuda. Cada vez que ejecuto la simulación, el primer año siempre funciona correctamente y luego Random.Next() comienza a devolver solamente 0.

¿Alguien tiene ideas sobre dónde debo buscar el siguiente error? ¡Gracias!

+2

Un ejemplo de código breve pero completo que reproduce el error sería útil tanto para usted como para la comunidad SO para ayudarlo a diagnosticar el problema. – LBushkin

+0

Hice una pregunta que creo que está relacionada y puede ayudar: http://stackoverflow.com/questions/2924599/parallel-loops-and-random-produce-odd-results – Mathias

+0

Duplicate of [System.Random sigue repitiendo el mismo valor] (http://stackoverflow.com/questions/295900/system-random-keeps-on-returning-the-same-value). –

Respuesta

18

Sospecho que está utilizando la misma instancia de Random simultáneamente en varios hilos. No hagas eso, no es seguro para subprocesos.

Opciones:

  • crear una nueva instancia de Random por hilo (ThreadStatic puede ayudar aquí)
  • utilizar una sola instancia de Random, pero sólo alguna vez lo utilizan en una cerradura.

Tengo un blog post con un código de muestra, pero lea los comentarios y hay buenas sugerencias para mejorarlo. Estoy planeando escribir otro artículo sobre la aleatoriedad en algún momento del futuro cercano ...

+0

¡Gracias, esto es exactamente lo que necesitaba! – Mandelbrot

5

No creo que la clase Random esté diseñada para ser segura para subprocesos (al mismo tiempo que se puede utilizar a partir de varios subprocesos), por lo que si comparte una sola instancia de esta manera, puede dañar el estado del generador aleatorio. evitando que funcione correctamente.

Se puede decorar la variable estática que contiene la referencia a la clase Random como ThreadStatic, lo que le permitirá mantener una instancia independiente por hilo:

[ThreadStatic] 
private static Random m_Random; // don't attempt to initialize this here... 

public void YourThreadStartMethod() 
{ 
    // initialize each random instance as each thread starts... 
    m_Random = new Random(); 
} 

Si está utilizando .NET 4.0, hay también la clase ThreadLocal<T>, que ayuda a facilitar la inicialización de una instancia por subproceso.

2

Random El objeto no es seguro para subprocesos. Para conseguir alrededor de eso, se puede utilizar este código robado de this answer:

class ThreadSafeRandom 
{ 
    private static Random random = new Random(); 

    public static int Next() 
    { 
     lock (random) 
     { 
      return random.Next(); 
     } 
    } 
} 

También es posible usar el RNGCryptoServiceProvider, lo que es seguro para subprocesos y también produce mejores datos aleatorios.

Cuestiones relacionadas