3

这个问题来自这样的知识,即当new Random()被快速调用时,它会以我假设基于的相同值播种DateTime.Now.Ticks

假设您在最新版本的 ASP.NET、IIS、.NET 等上有一个高流量的 Web 应用程序。它实现了一个在线赌场。我认为模拟老虎机需要从单个随机数流中提取。

在大容量情况下,您可能会得到两台具有相同随机数生成器的老虎机,从而导致过多的大头奖。我对伪随机生成器没有完全了解,但我的直觉是,要安全地实施在线赌场,您确实需要从一个只播种一次的生成器中提取。

我能想到的一个解决方案是一个同步队列,它有一个推送数字的线程,但我不知道如何在多站点应用程序之间同步它。

这种情况有一个好的/标准的解决方案吗?

更新:我正在处理的实际场景(实际上没有机会获得足够的音量来导致问题)

我的实际情况是,我有一个流量适中的 asp.net Web 表单站点,并且需要在每个请求上显示两个用户控件之一。我使用以下代码这样做:

// Randomly display one of (FreeCreditScore1, MyFreeScoreNow1)
private void ShowCreditScoreAd()
{
    FreeCreditScore1.Visible = (new Random().Next(2) == 1);
    MyFreeScoreNow1.Visible = !FreeCreditScore1.Visible;
}

如果我通过快速连续调用上面的代码来对上面的代码进行单元测试,它会失败,我开始明白原因是它new Random()在同一个“tick”中被调用。

也就是说,我确实相信我目前的实现已经足够了(请随时纠正我),但我很好奇如果我真的想严格要求它如何解决......

4

2 回答 2

2

只需用锁保护随机数生成器。除非您每秒向它发出数十万次调用,否则它将足够快。

public class MyRandomObject
{
    private readonly Random _rnd = new Random();

    public int Next()
    {
        lock (_rnd)
        {
            return _rnd.Next();
        }
    }
}

在您说“锁太慢”之前,请注意我在旧的 2.4 GHz 四核上进行了测试。当锁没有被争用时,获得一个随机数大约需要 70 纳秒。锁争用会降低性能,但您需要大量请求。

在 Web 应用程序中,您希望初始化其中的一个Application_Start,并使该单例可用于您的应用程序的其余部分。

有更快的方法,但它们更难以实施。一种方法是预先生成数百万个随机数(调用Random.NextBytes)并将它们存储在缓冲区中。用读/写锁保护它。当剩余值的数量达到某个阈值时,线程会获取写入器锁,阻止所有其他访问,直到它重新填充缓冲区。如果您使用其他一些随机数来源,这可能是您想要采用的方式。例如RNGCryptoServiceProvider.GetBytes方法(http://msdn.microsoft.com/en-us/library/system.security.cryptography.rngcryptoserviceprovider.getbytes.aspx)。

于 2013-02-20T04:20:26.120 回答
0

创建一个静态Random实例。通过生成 4 个加密安全的随机字节来播种它。您甚至可以使该Random实例[ThreadLocal]删除所有锁定。

我不知道为什么 BCL 不包含这样的东西并自动使用它来播种新实例。它很容易做到,提供完美的播种并完美地扩展到任意数量的线程。

于 2014-10-25T14:21:27.660 回答