#c# #.net #vb.net #performance
#c# #.net #vb.net #Производительность
Вопрос:
Мне интересно, происходит ли какой-то JIT-взлом с System.Ленивый, чтобы сделать вещи более производительными или это чисто «обычный класс»?
Со страницы http://msdn.microsoft.com/en-us/library/dd642331.aspx в нем говорится:
Используйте экземпляр Lazy (из T), чтобы отложить создание большого или ресурсоемкого объекта или выполнение ресурсоемкой задачи, особенно когда такое создание или выполнение может не произойти в течение срока службы программы.
но я могу отложить выполнение ресурсоемкой задачи, используя простой логический флаг, не так ли? Итак, в чем именно разница? (кроме System.У Lazy есть дополнительные накладные расходы без видимого увеличения «синтаксического сахара»)
С простым логическим флагом это просто:
if (!deferred) {
//run resource-intensive task
}
Редактировать:
вот пример
class Human{
System.Lazy<String> name = new System.Lazy<String>(() =>
{
//code here takes 4 seconds to run
return "the value";
});
String Name
{
get
{
return name.Value;
}
}
}
против
class Human
{
String name;
bool name_initiated;
String Name
{
get
{
if (!name_initiated)
{
//code here takes 4 seconds to run
name = "the value";
name_initiated = true;
}
return name;
}
}
}
6 Мая: теперь я часто использую это. И я действительно имею в виду очень много. я использую его всякий раз, когда мне нужно кэшировать данные (даже когда вычисление занимает 0,1 секунды или меньше). Отсюда мой вопрос, должен ли я беспокоиться? Теперь я знаю, что вы скажете мне профилировать приложение, но я сначала создаю библиотеку, прежде чем создавать приложение, и к тому времени, если в приложении возникнут проблемы, это будет означать серьезные изменения
Комментарии:
1. Можете ли вы показать технику, как отложить загрузку / выполнение с помощью простого логического флага? Вы можете начать с en.wikipedia.org/wiki/Call_by_need
2. Я позволю кому-нибудь менее ленивому сформулировать ответ… О, кстати, F # использует
Lazy<T>
и предоставляет немного синтаксического сахара.let ls = lazy([1;2;3])
3. @Nick я отредактировал вопрос, чтобы показать, как отложить загрузку / выполнение с помощью простого логического флага.
4. @Nick .. ссылка оправдывает использование отложенной оценки, о которой я не спорю. но это не оправдывает использование System. Ленивый вот почему я говорю, что мы можем добиться отложенной оценки с помощью простого логического флага зачем использовать System.Lazy?
5. @Pacerier, но как это там откладывается? Как запускаются вычисления? И какова семантика для этого флага? Выполнять задачу независимо от того, отложена она или нетерпелива? В любом случае, Джон Скит уже разместил хороший ответ. Взгляните. Если вам интересно, почему она вообще существует, взгляните на другую статью о том, как реализовать одноэлементный шаблон: yoda.arachsys.com/csharp/singleton.html это также можно сделать с помощью простого логического флага 😉
Ответ №1:
Да, вы могли бы отложить это с помощью простого логического флага. Конечно, вам нужно было бы обрабатывать изменчивость как флага, так и результата … и убедиться, что вы знали, чего хотите с точки зрения результата, если один поток запрашивает результат, пока он все еще вычисляется. О, и постарайтесь избегать блокировки, где это возможно. И сделать все это пуленепробиваемым с точки зрения потокобезопасности.
Нет, вообще никакой пользы от использования типа, созданного экспертами 😉
Серьезно: зачем делать это самостоятельно, если кто-то другой сделал это за вас? Зачем писать код для проверки флага, разрабатывать, как безопасно ждать, блокировать все и т.д. Даже если бы это было относительно просто сделать правильно, лучше, если это нужно сделать только один раз повторно.
Другим хорошим примером этого принципа является Nullable<T>
. Вы могли бы легко получить большую часть того же поведения самостоятельно (не упаковывать) или даже вообще не беспокоиться об инкапсуляции и просто сохранить флаг рядом с вашим обычным полем… но со встроенным типом вы получаете все это реализованным бесплатно, вместе с синтаксическим сахаром и т.д.
Комментарии:
1. @Джон, у тебя есть хорошая статья о реализации singleton csharpindepth.com/Articles/General/Singleton.aspx , вы можете связать это здесь, поскольку singleton также может быть «реализован» с помощью простого логического флага. Но, конечно, это немного оффтопично.
2. @Nick: Ну, вы можете реализовать шаблон singleton с помощью
Lazy<T>
, но на самом деле это не одно и то же… Я думаю, что предпочел бы не мутить воду в своем ответе, но ссылка все равно есть в комментариях 🙂3. @Джон, я просто хочу показать: все может быть сложнее, чем это выглядит в обзоре. Singleton (и ваши статья и книга) являются хорошей демонстрацией этого. Конечно, я не думаю
Lazy<T>
, что с одноэлементным шаблоном то же самое 🙂4. @Jon Skeet извините, я, наверное, не совсем ясно сформулировал свой вопрос. Я отредактировал свой вопрос на: должны ли мы использовать System. Ленивый для ресурсоемкой задачи (когда многопоточность не требуется)
5. @Pacerier: Контекст вашего вопроса все еще не ясен. Если вы можете показать нам полный пример, мы сможем сказать,
Lazy<T>
было бы ли это полезно. Это способ представления значения, которое будет вычислено при первой необходимости, а затем может быть использовано повторно. Если вы не находитесь в такой ситуации, это бесполезно.
Ответ №2:
Класс Lazy упрощает процесс. Это похоже на использование строки вместо массива символов. Технически это не обязательно, но может быть полезно.
Комментарии:
1.
String
на самом деле предоставляет ряд оптимизаций на уровне CLR, которые вы не смогли бы реализовать вне среды выполнения с помощью простогоchar[]
.2. @dahlbyk: В любом случае, основной смысл использования
String
заключается в семантической простоте. Вы могли бы выполнить интернирование самостоятельно, если бы захотели, не совсем тем же способом, но вы могли бы получить подавляющую часть производительности, если бы знали, что делаете.
Ответ №3:
Lazy<T>
это просто инкапсуляция наилучшего способа реализации ленивого синглтона. Если вы хотите потокобезопасности, это нечто большее, чем просто if(!initialized) instance = Initialize();
. Я обычно предполагаю, что команда BCL будет лучше в реализации, чем я.
Обновление: Основываясь на вашем примере, я бы сказал, что преимущество Lazy<>
заключается просто в меньшем количестве кода для поддержки. Помимо этого, они по существу эквивалентны. Мой совет: используйте Lazy<>
, потому что это легко, и переходите к более сложным задачам.
Комментарии:
1. извините, я, наверное, не совсем ясно сформулировал свой вопрос. Я отредактировал свой вопрос на: должны ли мы использовать System. Ленивый для ресурсоемкой задачи (когда многопоточность не требуется)
Ответ №4:
Класс Lazy выполняет всю работу по обеспечению потокобезопасности за вас, что является чем-то намного более сложным, чем кажется, для реализации вручную.
Комментарии:
1. извините, я, наверное, не совсем ясно сформулировал свой вопрос. Я отредактировал свой вопрос на: должны ли мы использовать System. Ленивый для ресурсоемкой задачи (когда многопоточность не требуется)