2009-10-07 15 views
5

Tengo problemas con la clase Random en .NET, estoy implementando una colección de subprocesos que funciona bien, excepto por un detalle más pequeño. La colección es Skip list y aquellos que estén familiarizados con ella saben que para cada nodo insertado necesito generar una nueva altura que sea <= CurrentMaxHeight+1, aquí está el código que estoy usando para hacer eso (sé que es muy ineficiente, pero funciona y esa es mi principal prioridad ahora)Problema con Random and Threads en .NET

int randomLevel() 
{ 
    int height = 1; 

    while(rnd.NextDouble() >= 0.5 && height < MaxHeight) 
    ++height; 

    return height; 
} 

mi problema aquí es que a veces me siguen dando sólo el 1 volver de este durante varios miles de elementos en una fila que mata el rendimiento de la lista de salto. La posibilidad de que 10.000 elementos generen solo 1 de este método en una fila, parece muy delgada (ocurre de manera bastante consistente).

así que estoy asumiendo (adivinanzas) que hay un problema con el objeto Random de alguna manera, pero no se sabe muy bien por dónde empezar a excavar alrededor. Entonces, ¿recurro a stackoverflow para ver si alguien tiene una idea?

Editar

El rnd-variable se declara en la clase SkipList<T>, y se accede a ella desde varios hilos (cada subproceso llama .Add en la recogida y agregar llamadas .randomLevel)

+0

¿Dónde se declara 'rnd'? – ChrisF

+0

es el randomlevel() llamado desde un hilo separado? – Benny

+0

declaración agregada para mayor claridad, se declara una vez y luego se llama desde varios subprocesos diferentes. – thr

Respuesta

4

Trate lock ing el objeto Random.

int RandomLevel() 
{ 
    int height = 1; 

    lock(rnd) 
    { 
     while(rnd.NextDouble >= 0.5 && height < MaxHeight) height++; 
    } 

    return height; 
} 

Puede haber un problema con colisiones cuando varios subprocesos tener acceso al objeto Random al mismo tiempo, y la semilla puede ser que consiga dañado. No puedo ofrecer ninguna idea sobre lo que podría ser específicamente, pero de acuerdo con MSDN, no se garantiza que los miembros de la instancia del tipo Random sean seguros para subprocesos, por lo que parece necesario un lock en cualquier caso.

+0

debe bloquearlo de esta manera: double d; lock (rnd) d = rnd.NextDouble(); este es un mejor rendimiento – Benny

+1

Bloquear el bucle while parece una mala idea. –

+1

Benny: No lo dudo, ¿pero me importa explicar por qué? En mi opinión, daría peor rendimiento ya que tengo que hacer la operación de bloqueo varias veces. – thr

1

Parece que su bucle se ejecuta menos de la mitad del tiempo que se llama - ¿es eso lo que está buscando (cuando un número aleatorio entre 0 y 1 es> 0.5? Esto podría explicar por qué está recibiendo "1 "con más frecuencia de lo que cabría esperar, al menos la mitad de las veces, ni siquiera ejecuta el ciclo que incrementa la altura, simplemente establece la altura en 1, no la cambia y luego devuelve" 1 ". No estoy familiarizado con las listas de omisiones, por lo que esto podría ser intencional, pero pensé que podría preguntar.

No estoy muy familiarizado con el trabajo con números aleatorios, pero ¿es posible que tenga un problema de siembra? Al aleatorizar el objeto Random cuando lo instancia, puede devolver un flujo predecible de números, en lugar de los que son verdaderamente aleatorios. Tal vez no cause el comportamiento. Estás viendo aquí, pero hay algo que considerar para seguir adelante.

3

No bloquearía todo el ciclo while. Simplemente bloquee las llamadas rnd.NextDouble().

int RandomLevel() 
{ 
    int height = 1; 
    double newRand; 

    lock(rnd) { newRand = rnd.NextDouble(); } 

    while(newRand >= 0.5 && height < MaxHeight) 
    { 
    height++; 
    lock(rnd) { newRand = rnd.NextDouble(); } 
    } 

    return height; 
} 

Aunque si el rendimiento es una consideración, sin duda me comparo ambas soluciones, ya que puede haber una diferencia en el rendimiento de un solo subproceso vs multiproceso.