MVC应用程序中的随机数生成

Sli*_*ggy 5 random asp.net-mvc static-members

如果每个请求只需要一个数字,那么在ASP.NET MVC应用程序中生成随机数的正确方法是什么?根据MSDN,为了获得足够质量的随机性,有必要使用创建一次的单个System.Random对象生成多个数字.由于为MVC中的每个请求创建了一个控制器类的新实例,因此我不能使用在控件的构造函数中为Random对象初始化的私有字段.那么我应该在MVC应用程序的哪个部分创建和存储Random对象?目前我将它存储在控制器类的静态字段中,并在使用它的action方法中懒惰地初始化它:

public class HomeController : Controller
{
    ...

    private static Random random;

    ...

    public ActionResult Download()
    {
        ...

        if (random == null)
            random = new Random();

        ...

    }
}
Run Code Online (Sandbox Code Playgroud)

由于"随机"字段可以被控制器类的多个实例访问,如果两个实例同时尝试初始化它,它的值是否可能被破坏?还有一个问题:我知道静态的生命周期是应用程序的生命周期,但是对于MVC应用程序,它是什么?它是从IIS启动到IIS关闭吗?

Gre*_*ech 10

理想情况下,您希望维护Random类的实例的时间长于单个页面的生命周期.难道不是通过把它在一个静态变量做到这一点; 该Random班是不是线程安全的,这会导致问题.来自文档:

任何实例成员都不保证是线程安全的.

我最喜欢的方法是来自Microsoft ParallelFX团队的RandomGen2包装器类(他们真正知道他们使用线程做什么),它使用每个线程的实例(主要是)无锁和线程安全的随机数.

public static class RandomGen2 
{ 
    private static Random _global = new Random(); 
    [ThreadStatic] 
    private static Random _local;

    public static int Next() 
    { 
        Random inst = _local; 
        if (inst == null) 
        { 
            int seed; 
            lock (_global) seed = _global.Next(); 
            _local = inst = new Random(seed); 
        } 
        return inst.Next(); 
    } 
}
Run Code Online (Sandbox Code Playgroud)

您可以按以下方式拨打电话:

var rand = RandomGen2.Next();
Run Code Online (Sandbox Code Playgroud)

您可能需要添加额外的方法来包装Random您想要访问的其他方法,我建议使用更好的名称ThreadSafeRandom,但它会证明原理.