随机数发生器返回零

Jac*_*cob 2 .net c# asp.net random

我有一个ASP.NET应用程序,它依赖于Random类来生成伪随机字符串.它使用以下代码(这是Google为应用程序SSO提供的更大范围的示例代码的一部分):

    public static class SamlUtility
{
    private static Random random = new Random();

    private static char[] charMapping =  { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p' };

    public static string CreateId()
    {
        byte[] bytes = new byte[20]; // 160 bits

        random.NextBytes(bytes);

        char[] chars = new char[40];

        for (int i = 0; i < bytes.Length; i++)
        {
            int left = (bytes[i] >> 4) & 0x0f;
            int right = bytes[i] & 0x0f;
            chars[i * 2] = charMapping[left];
            chars[i * 2 + 1] = charMapping[right];
        }

        return new string(chars);
    }
}
Run Code Online (Sandbox Code Playgroud)

这通常很有效,但有时会开始生成一串'a'.从我从调试中可以看出,Random只是停止返回随机数,而是反复填充具有相同值的字节.我通过使用GUID来修补此问题,但我很好奇原始代码中发生了什么.我假设某种形式的熵耗尽,但我在文档中找不到任何参考.此外,每次发生这种情况时,执行iisreset都会恢复正确的行为.

任何有关出错的建议都将不胜感激.

SLa*_*aks 6

Random班是不是线程安全的.
如果同时在多个线程上的同一实例上生成随机数,则其内部状态将被破坏,并且它将开始返回零.

您需要创建Random实例[ThreadStatic]以确保每个实例不被多个线程共享.
请注意,[ThreadStatic]字段的初始化程序只运行一次,因此您需要检查是否null每次使用该字段并在必要时进行初始化.
在种子中包含线程ID和当前时间以防止种子冲突也是一个好主意.

顺便提一下,注意Random班级不安全; 考虑使用该RNGCryptoServiceProvider课程

  • @Jacob:随机数不能保证唯一性! (3认同)
  • 不知何故,我怀疑获得锁定的时间(我的测试显示,当资源尚未锁定时,获取锁定大约0.05微秒)在ASP.NET网页的上下文中将变得非常重要.与响应请求所需的时间相比,"慢"锁是如此短的时间,这是无关紧要的.如果锁定速度非常重要,请使用SpinLock."锁定缓慢"是需要重新评估的传统智慧之一. (2认同)
  • @Jacob,如果要求唯一性,那么GUID不仅可以接受,它几乎是强制性的.这就是为什么GUID被发明,为所有计算机和所有时间提供有保证的唯一号码. (2认同)