为不同的"Random"实例创建不同的种子



人们通常会问为什么使用Random时他们总是会得到相同的数字。在他们的情况下,他们每次(而不是只使用一个实例),无力地创建一个新的Random实例,这当然会导致数字始终相同。但就我而言,我确实需要返回不同数字流的Random的几个实例。

使用硬编码的种子是我认为的一个坏主意,因为您在重新启动程序后一次又一次获得相同的值。这呢:

int seed1 = (int)DateTime.Now.Ticks - 13489565;
int seed2 = (int)DateTime.Now.Ticks - 5564;

我知道这看起来很愚蠢和天真,但是在每个重新启动和两个种子都应该不同之后,它会避免相同的值。也许

Random helper = new Random();
int seed1 = helper.Next(1, int.MaxValue);
int seed2 = helper.Next(1, int.MaxValue);

您可以看到,我在这里有点不创造,需要您的帮助。谢谢。

乔恩·斯基特(Jon Skeet)建议使用辅助Random对象和锁创建Random对象工厂。例如:

    public static Random NewRandom() 
    { 
        lock (globalLock) 
        { 
            return new Random(secondaryRandom.Next()); 
        } 
    } 

查看乔恩·斯基特(Jon Skeet)博客中的完整源代码。

我将使用您的第二种方法:

int randomCount = 10;
Random seeder = new Random();
var randoms = Enumerable.Range(0, randomCount)
    .Select(i => new Random(seeder.Next()))
    .ToList();

这使用LINQ创建了10个不同种子的随机实例的列表。因此,您需要using System.Linq;才能访问Select扩展方法。

您还可以将播种机重复使用为您的实例之一:

int randomCount = 10;
Random seeder = new Random();
var randoms = Enumerable.Range(0, randomCount - 1)
    .Select(i => new Random(seeder.Next()))
    .Concat(new [] { seeder })
    .ToList();

您可以使用加密生成器来创建种子,例如

public static Random CreateRandom()
{
    using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider())
    {
        byte[] bytes = new byte[4];
        rng.GetNonZeroBytes(bytes);
        int seed = BitConverter.ToInt32(bytes, 0);
        return new Random(seed);
    }
}

当然,如果您只需要INT,则可以使用RNGCryptoServiceProvider直接生成它们,尽管System.Random可能更快。

最新更新