2010-05-17 24 views
5

¿Cuál es la forma correcta de generar números aleatorios en una aplicación ASP.NET MVC si necesito exactamente un número por solicitud? Según MSDN, para obtener aleatoriedad de calidad suficiente, es necesario generar múltiples números usando un único objeto System.Random, creado una vez. Como se crea una nueva instancia de una clase de controlador para cada solicitud en MVC, no puedo usar un campo privado inicializado en el constructor del controlador para el objeto Random. Entonces, ¿en qué parte de la aplicación MVC debo crear y almacenar el objeto Random? Actualmente almaceno en un campo estático de la clase del controlador y perezosamente inicializarlo en el método de acción que lo utiliza:Generación aleatoria de números en aplicaciones MVC

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

    ... 

    public ActionResult Download() 
    { 
     ... 

     if (random == null) 
      random = new Random(); 

     ... 

    } 
} 

Puesto que el campo "aleatorio" se puede acceder por varias instancias de la clase del controlador, es posible que su valor se corrompa si dos instancias intentan inicializarlo simultáneamente? Y una pregunta más: sé que la vida útil de la estática es la duración de la aplicación, pero en el caso de una aplicación MVC, ¿qué es? ¿Es desde el inicio de IIS hasta el cierre de IIS?

Respuesta

10

Lo ideal es mantener una instancia de la clase Random durante más tiempo que el tiempo de vida de una sola página. Haz no haz esto poniéndolo en una variable estática; la clase Random no es segura para subprocesos y esto generará problemas. De the docs:

No se garantiza que los miembros de la instancia sean seguros para la ejecución de subprocesos.

Mi enfoque preferido es la clase RandomGen2 envoltorio del equipo de Microsoft ParallelFX (que realmente saben lo que están haciendo con rosca), que utiliza una instancia por hilo de números aleatorios (en su mayoría) de bloqueo-libre y seguras para subprocesos .

public static class RandomGen2 
{ 
    private static Random _global = new Random(); 
    [ThreadStatic] 
    private static Random _local; 

    public static int Next() 
    { 
     Random inst = _local; 
     if (inst == null) 
     { 
      int seed; 
      lock (_global) seed = _global.Next(); 
      _local = inst = new Random(seed); 
     } 
     return inst.Next(); 
    } 
} 

que luego se puede llamar simplemente de la siguiente manera:

var rand = RandomGen2.Next(); 

Es posible que tenga que añadir métodos adicionales para envolver los otros Random métodos que se desea acceder, y me gustaría sugerir un nombre mejor, tales como ThreadSafeRandom, pero demuestra el principio.

1

Puede tener un contructor estático en HomeController para ahorrarle tener que iniciarlo perezoso en cada método. Esto prácticamente garantiza que el Random solo se inicie una vez (la primera vez que se accede).

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

    static HomeController() 
    { 
     random = new Random(); 
    } 

    ... 

    public ActionResult Download() 
    { 
     ... 

     //use random - its already created. 


     ... 

    } 
} 
2

A menos que usted está lanzando a algunos demostración rápida o algo así, me gustaría poner esa responsabilidad en una capa de servicios o infraestructura (es decir, más que otra clase) y se deja manejar la vida de su generador de números aleatorios. No es Realmente el trabajo del controlador para gestionar esto de todos modos, y no tendrá que preocuparse cuando/si tiene otro controlador que necesita un número aleatorio.

Cuestiones relacionadas