为什么这个随机字符串生成器总是返回相同的值

本文关键字:返回 随机 字符串 为什么 | 更新日期: 2023-09-27 18:35:53

我今天遇到了一个奇怪的问题,我可以理解原因。 采用以下控制台程序。

internal class Program
    {
        private static void Main(string[] args)
        {
            string s1 = GenerateRandomCode(8);
            string s2 = GenerateRandomCode(8);
            string s3 = GenerateRandomCode(8);
        }
        public static string GenerateRandomCode(int length)
        {
            string charPool = "ABCDEFGOPQRSTUVWXY1234567890ZabcdefghijklmHIJKLMNnopqrstuvwxyz";
            StringBuilder rs = new StringBuilder();
            Random random = new Random();
            for (int i = 0; i < length; i++)
            {
                rs.Append(charPool[(int)(random.NextDouble() * charPool.Length)]);
            }
            return rs.ToString();
        }
    }

如果我在程序的 上放置一个断点并运行程序,则 s1、s2、s3 的值都相等。 现在,如果我在 s2 处放置一个断点,例如返回的值会有所不同。

似乎是某种并发问题? 这是怎么回事?

谢谢

为什么这个随机字符串生成器总是返回相同的值

随机数生成器实际上不是完全随机的:给定相同的种子值,多个实例将生成相同的随机序列。

不能说它比随机构造函数的 MSDN 文档更好

"默认种子值派生自系统时钟,并且具有 有限分辨率。因此,不同的随机对象是 通过调用默认构造函数紧密连续创建将 具有相同的默认种子值,因此将产生 相同的随机数集。此问题可以通过使用 单个随机对象以生成所有随机数。你也可以 通过修改系统返回的种子值来解决此问题 时钟,然后将此新种子值显式提供给 随机 (Int32) 构造函数。有关详细信息,请参阅 随机 (Int32) 构造函数。

因此,在您的情况下,您需要将 Random 实例保留为类级字段或函数参数,并且仅实例化一次。

因为您在每次调用GenerateRandomCode时都会实例化一个新Random,并且调用花费的时间非常短,所以所有 3 个 Random 对象最终都会使用相同的基于时间的种子,这意味着它们都将返回相同的第一个值。为 Random 对象创建一个字段,在程序开始时仅实例化一次,并GenerateRandomCode改用该Random实例 - 现在,当您调用 random.NextDouble() 时,您将获得不同的值。

new Random()呼叫拉出GenerateRandomCode

由于您每次都重新创建它并快速连续调用它,因此它可能获得相同的随机种子值。

您可以将其设置为静态,也可以使用依赖关系注入(将其传入)。

我相信这将解决问题。

原因:随机数实例在未给定任何种子值时DateTime.Now.Ticks值作为种子值。由于您的实例会以非常快的连续方式重新创建,因此该实例会使用相同的刻度进行种子设定。因此相同的随机数。

证明:在代码中放置一些断点。然后你会得到真正的随机值,因为当它击中调试器时,在你按 F10 或 F11 或 F5 之前会有时间损失。导致延时。

解决方案:创建 Random 类的静态实例,并在任何需要的地方使用其 Next 函数。