C#為什麼Random類不做靜態?
01-05
比如Console.WriteLine(Random.Create(100))多帶勁呀,為什麼還有new一個再調Next函數呢?
因為偽隨機數本質上是固定的數列,程序中各個部分擁有、管理自己的數列很正常。有時候還需藉助數列的決定性(deterministic),達致數據同步或是可重複地呈現相同的結果。
偽隨機數生成器設計成類才好用啊,不要被 C 語言的 rand() 或類似的設計影響了,C++11 標準庫還有各種偽隨機數類了。因為 Random 線程不安全,多線程訪問同一個實例可能會導致輸出的概率分布出問題
@Belleve 已經說出了原因,我就不重複了
至於題主想要通過靜態類實現的,又要線程安全,其實也不難做到——使用 ThreadLocal&因為是偽隨機數,根據種子生成的偽隨機數列應該是固定的,設計上就不應該是靜態類。說線程不安全的都是本末倒置……
因為不安全。
並不是說線程安全,而是有可能猜到隨機數大概的走向。
如果要弄清這個問題,你得從C語言的隨機函數開始研究,而且過程還有些複雜。線索:C語言,為什麼隨機函數會出現重複?
我第一次研究這個問題,是室友在魔獸世界裡擲骰子,我找了一個方法可以提高他擲骰子點數,不知道後續版本有沒有修復這個bug。這方便你在實例化Random的時候,設置不同的種子,生成不同的偽隨機數序列。當然你可能會說沒有這個需求。
你還可以繼承Random類,編寫自己的隨機數生成演算法,如果Random類做成靜態的,你就不能繼承了。當然你依然可能會說沒有這個需求。
接下來這個是不得不了,那就是線程安全問題,Random類是放在System命名空間下的,意味著很底層、很輕量,所以它自身沒有實現線程安全。不過,我們無法確定這是因還是果。你可以在應用程序啟動時,實例化一個全局可訪問的Random對象作為靜態欄位來使用。從多個線程訪問時,可以使用同步對象來確保同一時刻只有一個線程可以訪問這個對象。然後把它們統統封裝進一個靜態類中。然後你可能會問,為什麼微軟不從一開始就這樣實現這個Random類呢?因為濫用全局/靜態變數是不對的,無論線程安不安全。
那怎麼同時設置兩個種子?
這保證每個Random實例都是一個固定的偽隨機數生成器(PRNG),也就是說兩個Random實例如果用同一個隨機數種子的話生成的隨機數序列是一樣的(默認的種子是系統時間)。這個性質在某些地方會很有用,譬如密碼學裡的對稱流加密就可以用PRNG實現(總這個角度講Random其實也不太安全,RNGCyptoServiceProvider之類的CSPRNG更合適),這時候種子就是秘鑰;再譬如說你想debug一個隨機演算法,用一個確定的種子和PRNG就可以確保兩次執行生成的偽隨機序列是一樣的,就能重複演算法過程。
推薦閱讀:
※關於 C# 中「string + int」的執行機制的疑惑?
※既然在變數前加一個&就可以得到地址,為什麼還需要指針?
※有哪些語言可以做到:List<T> 實現介面 I(或繼承某個類)當且僅當 T 實現 I?
※關於MSIL中的Nop的問題?
※xamarin 怎麼發音?