2010-05-17 23 views
5

如果每次請求只需要一個數字,在ASP.NET MVC應用程序中生成隨機數的正確方法是什麼?根據MSDN的說法,爲了獲得足夠的質量隨機性,必須使用一次創建的單個System.Random對象生成多個數字。由於爲MVC中的每個請求創建了一個控制器類的新實例,因此我無法使用在控制器的構造函數中爲Random對象初始化的私有字段。那麼,我應該創建和存儲Random對象的哪個部分?目前,我把它存儲在控制器類的靜態字段,懶洋洋地初始化它在使用它的操作方法:MVC應用程序中的隨機數生成

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

    ... 

    public ActionResult Download() 
    { 
     ... 

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

     ... 

    } 
} 

由於「隨機」字段可以由控制器類的多個實例訪問,是它如果兩個實例試圖同時初始化它的值,可能會損壞它的值?還有一個問題:我知道靜態的生命週期是應用程序的生命週期,但是在MVC應用程序的情況下它是什麼?它是從IIS啓動直到IIS關機?

回答

10

理想情況下,您希望維護Random類的實例的時間長於單個頁面的生命週期。做不是通過把它放在一個靜態變量中做到這一點; Random類不是線程安全的,這會導致問題。從the docs

任何實例成員不保證是線程安全的。

我最喜歡的方法是從Microsoft ParallelFX隊伍(誰真正知道他們正在使用的線程做什麼)的RandomGen2包裝類,它使用每線程一個實例(大部分)無鎖,線程安全的隨機數。

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

然後您可以只是調用如下:

var rand = RandomGen2.Next(); 

您可能需要添加額外的方法來包裝你要訪問其他Random方法,我會建議一個更好的名字,例如作爲ThreadSafeRandom,但它表明了原則。

1

您可以在HomeController中有一個靜態構造函數來保存您不必在每種方法中對其進行延遲初始化。這幾乎可以確保Random只被初始化一次(第一次被訪問)。

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

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

    ... 

    public ActionResult Download() 
    { 
     ... 

     //use random - its already created. 


     ... 

    } 
} 
2

除非你扔在一起的一些快速演示或什麼的,我會把這個責任到服務或基礎設施層(即,只是一個類),並讓它管理您的隨機數生成器的壽命。這不是真的是控制器的工作來管理這個 - 無論何時/如果您有另一個需要隨機數的控制器,您都不會擔心它。