TIPS-避免連續快速建立Random物件
這是在玩三門問題時程式沒寫好遇到的狀況,做個筆記。
以下程式會連續建立1000個Test物件,Test物件建構式中會產生A, B, C三個隨機亂數。大家有發現其中存在什麼問題嗎?
using System;
namespace TestRandom
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 1000; i++)
{
Test t = new Test();
Console.WriteLine(
"NO:{0:000} A:{1:00} B:{2:00} C:{3:00}",
i, t.A, t.B, t.C);
}
Console.Read();
}
}
public class Test
{
public int A, B, C;
Random rnd = new Random();
public Test()
{
A = rnd.Next(100);
B = rnd.Next(100);
C = rnd.Next(100);
}
}
}
實地執行一下程式,你會發現亂數怎麼一點都不亂,例如以下結果:
NO:978 A:66 B:39 C:77
NO:979 A:66 B:39 C:77
NO:980 A:66 B:39 C:77
NO:981 A:66 B:39 C:77
NO:982 A:66 B:39 C:77
NO:983 A:66 B:39 C:77
NO:984 A:66 B:39 C:77
NO:985 A:66 B:39 C:77
NO:986 A:49 B:79 C:25
NO:987 A:49 B:79 C:25
NO:988 A:49 B:79 C:25
NO:989 A:49 B:79 C:25
NO:990 A:49 B:79 C:25
NO:991 A:49 B:79 C:25
NO:992 A:49 B:79 C:25
NO:993 A:49 B:79 C:25
NO:994 A:49 B:79 C:25
NO:995 A:49 B:79 C:25
NO:996 A:49 B:79 C:25
NO:997 A:49 B:79 C:25
NO:998 A:49 B:79 C:25
NO:999 A:49 B:79 C:25
我們會得到連續N組A, B, C亂數相同的結果,一陣子後變成另外一組亂數再重複N次,再隔一陣子後再換成另一組亂數重複N次... 問題出在亂數種子! MSDN中有詳細說明:
亂數的產生始於種子值。如果重複使用相同的種子會產生相同的連續數字。其中一個產生不同序列的方法是讓種子值時間相依,由此以每個 Random 的新執行個體 (Instance) 產生不同的系列。根據預設,Random 類別的無參數建構函式會使用系統時鐘來產生其種子值,而參數化的建構函式可以根據目前時間的刻度數目而接受 Int32 值。然而,因為時鐘的解析度有限,所以若使用無參數的建構函式在極短時間內連續建立不同的 Random 物件,就會建立亂數產生器,這些產生器會產生序列完全相同的亂數。
所以祕訣在於:
不要快速地連續new Random(),應該建立一個Random後重複使用。
以先前程式為例,最簡單的修改方式是把rnd宣告成靜態變數,全部的Test物件共用一份,就能解決問題囉!
public class Test
{
public int A, B, C;
static Random rnd = new Random();
public Test()
{
A = rnd.Next(100);
B = rnd.Next(100);
C = rnd.Next(100);
}
}