【问题标题】:Quickly generating random numbers in C#在 C# 中快速生成随机数
【发布时间】:2012-03-13 05:54:05
【问题描述】:

我正在创建一个程序,该程序创建几个具有随机确定颜色的面板,这些面板将每 20 毫秒左右增加/减少一些随机常数,以创建平滑、起伏的颜色。为此,我一直在使用 Random 类的 Next(int) 方法。对于单个实例,这非常有效——每次我运行程序时,我都会得到不同的颜色以不同的速率变化。当我尝试创建多个面板时,问题就出现了——如果不是全部的话,大多数面板的外观和行为都相同,这意味着所有随机生成的数字都是相同的。我假设这是快速连续生成所有伪随机数的结果,导致它们都基于同一个种子。

有没有比使用 Random 类快速连续生成随机整数以确保它们不相同更好的方法?如果 C# 中还没有内置任何方法,是否有任何直接的方法来开发伪随机数生成器(请记住,这是我第一次尝试使用 C#)?

【问题讨论】:

  • 您是否每次都重新初始化/重新创建 PRNG 对象?一个像样的 PRNG 不应该可靠地产生与您描述的相同的数字。

标签: c# random


【解决方案1】:

不要使用默认构造函数来使用 Random 类的多个实例。如果它们都在同一个时间片内初始化,它们都将具有相同的种子并生成相同的随机数序列,请使用 you can pass in a seed 的构造函数并将不同的种子传递给每个实例。

Random rand0, rand1, rand2;

void init()
{
      int baseSeed = (int) DateTime.Now.Ticks;
      rand0 = new Random(baseSeed);
      rand1 = new Random(baseSeed + 1);
      rand2 = new Random(baseSeed + 2);
}

此外,每个线程只需要一个对象,如果所有面板都在同一个线程上,则对所有面板使用相同的 Random 对象。

【讨论】:

  • 或者,或者,只创建一个 Random 的中心实例并将其用于所有随机数生成。
  • @AvnerShahar-Kashtan:嗯,每个线程一个。它们不是线程安全的。
  • 重用现有的随机数生成器通常比每次都创建一个带有种子的新实例更简单。毕竟,如果您必须保留种子,为什么不保留对 Random 的引用呢?
  • @JonSkeet 我以为他在重复使用它们,但很快就制作了多个实例,我更新了我的答案以进行澄清。
  • @ScottChamberlain:如果Random 实例不在 在同一个线程上,则需要更加小心才能自动更新种子 :)(为什么您将种子限制在 0-65535 范围内吗?)
【解决方案2】:
如果您不需要加密安全的随机数,

Random 很好 - 但您可能会在每次需要数字时创建一个新实例,而不是始终使用 one 实例。

当您创建 Random 的新实例时,它将以“当前时间”作为种子 - 因此,如果您快速连续创建两个实例,您最终会得到两个具有相同种子的实例,因此相同号码(当您使用相同的呼叫时)。

通常最好使用Random 的单个实例 - 或者更确切地说,每个线程一个,因为它不是线程安全的。

查看我的article on the topic 了解各种方法。

【讨论】:

    【解决方案3】:

    我更喜欢RNGCryptoServiceProvider。它大致与Random 一样快,并且在我的非正式测试中往往会产生更多独特的价值。您还可以避免任何与播种有关的不良行为(例如其他人所描述的)。

    但是,您不能保证唯一性(否则它不会是随机的)。如果您需要永久跟踪唯一值(这听起来不像您希望这样做),您可以使用数据库或 Dictionary 如果您只关心生成一组唯一数字,则随机值是关键记忆。如果键已存在,则拒绝该值并生成另一个值。

    using System.Security.Cryptography;
    
    ...
    
    RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
    byte[] bytes = new byte[8];
    crypto.GetBytes( bytes );
    long value = BitConverter.ToInt64( bytes, 0 );
    

    【讨论】:

      【解决方案4】:

      如果您有多个 Random 类实例产生相同的随机数序列,那么您必须使用相同的种子创建每个实例。例如:

      对此最可能的解释是,您是这样创建它们的:

      var rng = new Random();
      

      并在同一时间点创建每个实例。此构造函数使用当前时间为 RNG 播种,如果您在同一时间点创建它们,它们都将在同一时间播种。

      通过使用不同的种子创建每个实例来解决问题。或者创建一个 RNG 并在所有面板之间共享。

      【讨论】:

        【解决方案5】:

        如上所述,您可以使用随机类的单个实例。但是,如果由于某种原因这是不可取的(即您想要运行多个线程并且不想要任何争用),那么您可以使用多个实例,只要您将每个生成器的种子初始化为随机或伪 -随机生成的种子。

        对于这个初始种子生成,您将需要使用相同的随机生成器。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-02-21
          • 1970-01-01
          • 1970-01-01
          • 2010-11-05
          • 2020-05-23
          • 1970-01-01
          • 1970-01-01
          • 2020-10-13
          相关资源
          最近更新 更多