2010-05-17 16 views
5

Qual è il modo corretto di generare numeri casuali in un'applicazione ASP.NET MVC se ho bisogno di un numero esatto per richiesta? Secondo MSDN, per ottenere casualità di qualità sufficiente, è necessario generare più numeri usando un singolo oggetto System.Random, creato una volta. Poiché una nuova istanza di una classe controller viene creata per ogni richiesta in MVC, non è possibile utilizzare un campo privato inizializzato nel costruttore del controllore per l'oggetto casuale. Quindi in quale parte dell'applicazione MVC dovrei creare e memorizzare l'oggetto casuale? Attualmente mi conservarlo in un campo statico della classe controller e pigramente inizializzarlo nel metodo di azione che lo utilizza:Generazione di numeri casuali in applicazioni MVC

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

    ... 

    public ActionResult Download() 
    { 
     ... 

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

     ... 

    } 
} 

Poiché il campo "random" si può accedere da più istanze della classe controller, è possibile che il suo valore si corrompa se due istanze tentano di inizializzarlo contemporaneamente? E un'altra domanda: so che la durata della statistica è la durata dell'applicazione, ma in caso di un'app MVC che cos'è? Proviene dall'avvio di IIS fino all'arresto di IIS?

risposta

10

Idealmente si desidera mantenere un'istanza della classe Random per un periodo più lungo della durata di una singola pagina. Non fare non inserendolo in una variabile statica; la classe Random non è thread-safe e questo si tradurrà in problemi. Da the docs:

Qualsiasi istanza membri non è garantita per essere thread-safe.

Il mio approccio preferito è la classe RandomGen2 involucro dal team di Microsoft ParallelFX (che davvero sanno quello che stanno facendo con filettatura), che utilizza un'istanza per thread per i numeri casuali (per lo più)-lock libera e thread-safe .

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(); 
    } 
} 

che è quindi possibile chiamare i seguenti:

var rand = RandomGen2.Next(); 

Potrebbe essere necessario aggiungere metodi aggiuntivi per avvolgere gli altri metodi Random si desidera accedere, e io suggerirei un nome migliore, quali come ThreadSafeRandom, ma dimostra il principio.

1

Si potrebbe avere un contructor statico in HomeController per evitare di dover inizializzare in ogni metodo. Ciò assicura che lo Random venga inizializzato solo una volta (la prima volta che si accede).

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

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

    ... 

    public ActionResult Download() 
    { 
     ... 

     //use random - its already created. 


     ... 

    } 
} 
2

A meno che non si sta lanciando insieme alcuni demo veloce o qualcosa, vorrei mettere questa responsabilità in un livello di servizio o le infrastrutture (ad esempio, solo un altro classe) e lasciarlo gestire la durata del generatore di numeri casuali. Non è in realtà il lavoro del controller per gestirlo comunque - e non ti preoccuperai quando/se hai un altro controller che ha bisogno di un numero casuale.

Problemi correlati