Генерация случайных чисел в приложениях MVC - PullRequest
5 голосов
/ 17 мая 2010

Как правильно генерировать случайные числа в приложении 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?

Ответы [ 3 ]

10 голосов
/ 17 мая 2010

В идеале вы хотите поддерживать экземпляр класса Random дольше, чем время жизни одной страницы. Do not сделать это, поместив его в статическую переменную; класс Random не является потокобезопасным, и это приведет к проблемам. От документов :

Любые члены экземпляра не гарантируют поточно-ориентированность.

Мой любимый подход - это класс-оболочка RandomGen2 от команды Microsoft ParallelFX (который действительно знает, что они делают с многопоточностью), который использует экземпляр для каждого потока (в основном) без блокировок и потоков. безопасные случайные числа.

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, но оно демонстрирует принцип.

2 голосов
/ 17 мая 2010

Если вы не собираете небольшую демонстрацию или что-то в этом роде, я бы отнес эту ответственность на уровень обслуживания или инфраструктуры (т. Е. Просто на другой класс) и позволил бы ему управлять временем жизни вашего генератора случайных чисел. В любом случае это не действительно работа контроллера, и вам не придется об этом беспокоиться, когда / если у вас есть другой контроллер, которому нужно случайное число.

1 голос
/ 17 мая 2010

У вас может быть статический конструктор в HomeController, чтобы избавить вас от необходимости лениво инициализировать его в каждом методе. Это в значительной степени гарантирует, что Random инициализируется только один раз (при первом обращении к нему).

public class HomeController : Controller
{
    ...

    private static Random random;

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

    ...

    public ActionResult Download()
    {
        ...

        //use random - its already created.


        ...

    }
}
...