Использование Lazy<T> плохо для производительности?

Недавно у меня были некоторые проблемы с классом singelton, который лениво инициализировал словарь, где второй поток попытался бы использовать его до того, как он был фактически заполнен. Поэтому я реализовал инициализацию переменной через Lazy<T> учебный класс.

Вот мой код:

private static Dictionary<string, string> GroupDefaults
{
    get { return mGroupDefaults.Value; }
}
private static Lazy<Dictionary<string, string>> mGroupDefaults =
    new Lazy<Dictionary<string,string>>(delegate
    {
        Dictionary<string, string> defaults = new Dictionary<string, string>();
        foreach (KeyValuePair<string, UnitGroup> groupDef in Groups)
            defaults.Add(groupDef.Key, groupDef.Value.First().Key);
        return defaults;
    });

Это решило проблему, и теперь я рассматриваю возможность сделать это моей обычной практикой использования Lazy<T> класс везде я делаю ленивую инициализацию, чтобы избежать возможных проблем с многопоточностью. В общем, я хотел бы знать, является ли это хорошей / обычной практикой? Или это будет вредно для производительности или что-то?

4 ответа

Решение

Трудно сказать, не зная, какой тип ограничений производительности у вас есть, но по моему опыту, одноразовая инициализация редко является узким местом (поскольку по определению это происходит только один раз). Lazy<T> был написан, чтобы предоставить вам именно эту услугу, поэтому я бы порекомендовал использовать его.

Из документации я нахожу следующее:

Если в конструкторе Lazy не передается делегат, упакованный тип создается с помощью Activator.CreateInstance при первом доступе к свойству value. Если тип не имеет конструктора по умолчанию, генерируется исключение во время выполнения.

Activator.CreateInstance это метод, который, как известно, плохо влияет на производительность. Однако в вашем случае это не кажется проблемой, и в любом случае, как сказал dlev, вызов метода один раз не будет проблемой. Я не видела Lazy<T> используется очень часто, но я не вижу никаких причин не использовать его в вашем случае.

Если это для одиночного, статический конструктор может быть тем, что вы хотите. Что-то вроде:

class MySingleton
{
    static MySingleton()
    {
         Instance().InitDict();
    }
}

Я думаю, что вы можете использовать Lazy не по назначению. Ленивый должен использоваться в ситуациях, когда что-то имеет большие затраты на инициализацию, но есть вероятность того, что это не может быть использовано в течение срока службы объекта.

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

Другие вопросы по тегам