7

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

public class HomeController : Controller
{
    ...

    private static Random random;

    ...

    public ActionResult Download()
    {
        ...

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

        ...

    }
}

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

4

3 回答 3

12

理想情况下,您希望将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(); 
    } 
}

然后您可以按如下方式调用:

var rand = RandomGen2.Next();

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

于 2010-05-17T07:59:10.923 回答
3

除非您将一些快速演示或其他东西放在一起,否则我会将这个责任放入服务或基础设施层(即,只是另一个类)并让它管理您的随机数生成器的生命周期。无论如何,管理它并不是控制器的真正工作 - 当/如果您有另一个需要随机数的控制器时,您将不必担心它。

于 2010-05-17T07:51:29.037 回答
1

您可以有一个静态构造函数,HomeController以节省您必须在每个方法中延迟初始化它。这几乎可以确保Random唯一的初始化一次(第一次访问它)。

public class HomeController : Controller
{
    ...

    private static Random random;

    static HomeController()
    {
        random = new Random();
    }

    ...

    public ActionResult Download()
    {
        ...

        //use random - its already created.


        ...

    }
}
于 2010-05-17T07:49:06.580 回答