2010-05-17 28 views
5

Jaki jest poprawny sposób generowania liczb losowych w aplikacji ASP.NET MVC, jeśli potrzebuję dokładnie jednego numeru na żądanie? Według MSDN, aby uzyskać losowość o odpowiedniej jakości, konieczne jest generowanie wielu liczb za pomocą pojedynczego obiektu System.Random, utworzonego raz. Ponieważ dla każdego żądania w MVC tworzone jest nowe wystąpienie klasy kontrolera, nie mogę użyć prywatnego pola zainicjowanego w konstruktorze kontrolera dla obiektu losowego. Więc w jakiej części aplikacji MVC powinienem utworzyć i przechowywać obiekt losowy? Obecnie przechowywać go w statycznym polu klasie kontrolera i leniwie go zainicjować w sposobie działania, który wykorzystuje go:Generowanie liczb losowych w aplikacjach MVC

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

    ... 

    public ActionResult Download() 
    { 
     ... 

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

     ... 

    } 
} 

Ponieważ „random” pole może być dostępne przez wiele instancji klasy kontrolera, to jest możliwe, że jego wartość zostanie uszkodzona, jeśli dwa wystąpienia spróbują go zainicjować jednocześnie? I jeszcze jedno pytanie: Wiem, że czas życia statyki to czas życia aplikacji, ale w przypadku aplikacji MVC, co to jest? Czy to od uruchomienia IIS do zamknięcia IIS?

Odpowiedz

10

Idealnie chcesz zachować instancję klasy Random dłużej niż czas życia pojedynczej strony. Wykonaj , a nie zrobić to poprzez umieszczenie go w zmiennej statycznej; Klasa Random nie jest wątkowo bezpieczna, a to spowoduje problemy. Od the docs:

Żaden członek nie może zagwarantować bezpieczeństwa wątku.

Moim ulubionym sposobem jest klasa RandomGen2 wrapper z zespołu Microsoft ParallelFX (którzy naprawdę wiedzą, co robią z gwintem), który korzysta z instancji za wątku na (głównie) lock-wolny i bezpieczny wątku liczb losowych .

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

których można następnie zadzwoń następująco:

var rand = RandomGen2.Next(); 

może trzeba dodać dodatkowe metody zawinąć inne Random metod, które chcesz uzyskać dostęp, a ja proponuję lepsze taką nazwę jako ThreadSafeRandom, ale demonstruje zasadę.

1

Możesz mieć statycznego contructor w HomeController, aby zaoszczędzić leniwy zainicjować go w każdej metodzie. To prawie gwarantuje, że tylko Random zostanie zainicjowany tylko raz (po raz pierwszy jest dostępny).

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

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

    ... 

    public ActionResult Download() 
    { 
     ... 

     //use random - its already created. 


     ... 

    } 
} 
2

Chyba że rzucanie razem jakiś szybki demo lub coś, chciałbym umieścić tę odpowiedzialność w warstwie usług lub infrastruktury (czyli po prostu inna klasa) i pozwolić mu zarządzać żywotność swojego generatora liczb losowych. To nie jest zadaniem sterownika, by tak czy inaczej to zarządzać - i nie będziesz się tym martwić, gdy/jeśli masz innego kontrolera, który potrzebuje losowej liczby.

Powiązane problemy