2012-03-16 19 views
8

Esta es la culminación de un Skeet posting for a random provider:aleatoria en .Net 3.5

public static class RandomProvider 
{  
    private static int seed = Environment.TickCount; 

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

    public static Random GetThreadRandom() 
    { 
     return randomWrapper.Value; 
    } 
} 

me gustaría usar el mismo concepto en un proyecto .NET 3.5, por lo ThreadLocal no es una opción.

¿Cómo modificarías el código para tener un proveedor aleatorio seguro para hilos sin la ayuda de ThreadLocal?

ACTUALIZACIÓN

Ok, voy con Simon [ThreadStatic] por ahora, ya que entiendo que la mejor. Mucha información buena aquí para revisar y repensar a medida que el tiempo lo permita. ¡Gracias a todos!

public static class RandomProvider 
{ 
    private static int _seed = Environment.TickCount; 

    [ThreadStatic] 
    private static Random _random; 

    /// <summary> 
    /// Gets the thread safe random. 
    /// </summary> 
    /// <returns></returns> 
    public static Random GetThreadRandom() { return _random ?? (_random = new Random(Interlocked.Increment(ref _seed))); } 
} 
+1

También hay un seguimiento en el artículo: https://msmvps.com/blogs/jon_skeet/archive/2009/11/04/revisiting-randomness.aspx donde explica otras estrategias de seguridad de hilos. – CodesInChaos

Respuesta

8

Puede utilizar el ThreadStaticAttribute

[ThreadStatic] 
private static Random _random; 

private static Random Random 
{ 
    get 
    { 
     int seed = Environment.TickCount; 

     return _random ?? (_random = new Random(Interlocked.Increment(ref seed))) 
    } 
} 
+0

Agradable y vale +1, pero suena demasiado fácil, después de leer la opinión de Skeet. ¿Qué ventaja tendría la implementación de ThreadLocal sobre esto? – Berryl

+0

No conocía 'ThreadLocal' antes de esta pregunta, pero a primera vista la única ventaja que veo es que a' ThreadLocal' se le puede dar un método de fábrica para inicializar el valor, por lo que no es necesario comprobar ' null' – Terkel

+0

La publicación de Skeets parece indicar que 'ThreadLocal' es un poco más rápido, pero en mis propias pruebas no pude reproducir eso. Fui con 'ThreadLocal' para mi biblioteca de generador aleatorio, pero desafortunadamente usa contratos de código, y por lo tanto solo funciona en .net 4. – CodesInChaos

9

¿Cómo te modificar el código para tener un proveedor de azar seguro para hilos sin la ayuda de ThreadLocal?

Jon responde a su pregunta en el artículo se ha vinculado a:

uso un caso, sino también el uso de una cerradura que cada persona que llama tiene que recordar para adquirir mientras se está utilizando el generador de números aleatorios. Eso se puede simplificar mediante el uso de un contenedor que hace el bloqueo por usted, pero en un sistema con varios subprocesos potencialmente perderá mucho tiempo esperando bloqueos.

Así que simplemente asegúrelo siempre en el envoltorio, y desbloquéelo cuando haya terminado.

Si eso es lo suficientemente barato, genial, es lo suficientemente barato.

Si eso no es lo suficientemente barato, entonces tiene dos opciones. Primero, hazlo más económico. En segundo lugar, escribe una implementación de seguridad de subprocesos de un generador de números pseudoaleatorios que se puede usar sin bloquear.

Hay varias maneras de hacerlo más barato. Por ejemplo, puedes intercambiar espacio por tiempo; podría generar una matriz de cien mil números aleatorios cuando se inicie el programa, y ​​luego escribir un algoritmo sin bloqueo que ofrezca valores aleatorios calculados previamente de la matriz. Cuando se quede sin valores, genere otros cien mil valores en una matriz y cambie la nueva matriz por la anterior.

Tiene la desventaja de que su consumo de memoria es aproximadamente cien mil veces mayor de lo que podría ser, y que cada cien mil números de repente se vuelve muy lento y luego se acelera de nuevo. Si eso no es aceptable, entonces presenta una estrategia que es aceptable. Tú eres el único que sabe cuál es el rendimiento aceptable y el que no.

O, como dije, escriba la suya propia si no le gusta la que se le proporciona. Escriba una implementación de ejecución aleatoria de Random con un rendimiento aceptable y utilícela desde varios hilos.

¡Vi lo que dijo Jon sobre encerrar el envoltorio pero no estoy seguro de cómo se vería el código!

Algo así como:

sealed class SafeRandom 
{ 
    private Random random = new Random(); 
    public int Next() 
    { 
     lock(random) 
     { 
      return random.Next(); 
     } 
    } 
} 

Ahora, cada vez que llame a continuación, se obtiene un bloqueo. (Siempre bloquee un objeto privado ; de esa manera usted sabe que su código es el único código que lo bloquea!) Si dos hilos llaman "al mismo tiempo" a continuación, el "perdedor" bloquea hasta que el "ganador" se va el siguiente método.

Si quería, incluso se podría hacer que el objeto SafeRandom una clase estática:

static class SafeRandom 
{ 
    private static Random random = new Random(); 
    public static int Next() 
    { 
     lock(random) 
     { 
      return random.Next(); 
     } 
    } 
} 

y ahora se puede llamar SafeRandom.Next() desde cualquier hilo.

+0

Hmmm, como * usted * sabe de lo que está hablando: -) – Berryl

+0

Sí, vi lo que dijo Jon sobre encerrar el envoltorio pero no estoy seguro de cómo se vería el código. – Berryl

+0

@Berryl: mira mi actualización. –

1

Acabo de leer el enlace a "C# en Profundidad" y, aunque estoy de acuerdo con el hecho de que Random no es peligroso, realmente usaría un enfoque diferente para deshacerse del problema, es decir, por razones de rendimiento .

crear instancias de un motor aleatorio es una acción bastante pesado, por lo que prefiero mantener sólo una instancia y que sea hilo de seguridad mediante el uso de cerraduras:

public static class RandomProvider 
{  
    private static Random randomEngine = new Random(Environment.TickCount); 

    private static object randomLock = new object(); 

    public static int GetRandomValue() 
    { 
     lock(randomLock) 
     { 
      return randomEngine.Next(); 
     } 
    } 
} 

HTH

+0

. publicar un código diferente? Esto se parece al código 4.0 original, ¿no? – Berryl

+0

No: ya no usa ThreadLocal, y tampoco usa ThreadStatic –