Re[2]: В чем полезность ленивых вычислений
От: Tom Россия http://www.RSDN.ru
Дата: 24.10.10 09:24
Оценка: 2 (2) +4
Здравствуйте, dilmah, Вы писали:

А>>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


D>практическая польза в том, что ты можешь писать более простой и понятный код, не волнуясь об оптимизации, зная что она произойдет автоматически.

Уж никак не более просто и понятный, ибо явная инициализация всегда на порядок проще и понятнее, чем ленивая, которая произойдёт непонятно когда, в каком потоке, и непонятно к чему приведёт при возникновении какого либо исключения
Народная мудрось
всем все никому ничего(с).
Re: В чем полезность ленивых вычислений
От: Tom Россия http://www.RSDN.ru
Дата: 24.10.10 09:28
Оценка: 1 (1) +3
Здравствуйте, Аноним, Вы писали:

А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.

Примера из объектов реального мира я ещё не видел. Лично сам считаю что в 99% случаев ленивые вычисления являются проблемой дизайна.
Сами же ленивые вычисления только добавляют сложности в проекте ибо:
1. Не известен момент в который будет произведено вычисление
2. Не известен поток
3. Не известен call stack
4. При возникновении ошибки невозможно предсказать поведение системы

Ну и KISS ленивые вычисления явно нарушают.

В общем если вдруг вам нужны ленивые вычисления — нужно 10 раз подумать почему. Почему вы не можете явно их выполнить в вполне детерминированные момент времени.
Народная мудрось
всем все никому ничего(с).
Re: В чем полезность ленивых вычислений
От: dilmah США  
Дата: 24.10.10 08:06
Оценка: -1 :)
А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.

практическая польза в том, что ты можешь писать более простой и понятный код, не волнуясь об оптимизации, зная что она произойдет автоматически.
Re: В чем полезность ленивых вычислений
От: poldhiir  
Дата: 25.10.10 00:11
Оценка: +2
Здравствуйте, Аноним, Вы писали:

А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.

я делал ленивую аллокацию памяти. был набо функций типа foo(HANDLE *h, ...), которым _иногда_ требовался буфер памяти, упрятанный в HANDLE, но чаще всего он просто болтался без дела. по спецификации буфер должен быть выделен и иницилизирован внутри INIT(HANDLE *h), но реально буфер выделялся только когда в нем возникала необходимость. причем такая имплементация спецификации не противоречила, но здорово экономила память в ситуации когда у нас много HANDLE (а их было реально много), но только некоторым из них нужен буфер.

так же ленивую загрузку внешних модулей делал. функция load_module(char *module_name) подгружала модуль только в момент превого вызова функции из него. плюс там еще была предусмотрена возможность фоновой загрузки, когда ЦП бездействует -- тогда на основе предшествующих запусков делались предсказания какие модули будут загружены и они грузились, когда юзер ничего не делает. в частности, модуль печати. грузить его сразу -- плохо, т.к. не факт, что он нужен. грузить его при первом вызове -- тормоза при нажатии на CTRL-P, нервирующие юзера. грузить его в фоне -- наименьшее зло ИМХО.
Re[2]: В чем полезность ленивых вычислений
От: Pavel Dvorkin Россия  
Дата: 25.10.10 10:20
Оценка: +2
Здравствуйте, Sinclair, Вы писали:

Согласен, но это лишь один случай, хоть и довольно распространенный. Кстати, мои любимые VirtualAloc и memory-mapped files есть как раз иллюстрация этого случая. Заказ потенциально бесконечного пространства с тем, чтобы потом использовать, скорее всего, лишь небольшую часть.

Но есть и другой случай. Ситуация, когда попросту непонятно, надо что-то делать или нет.

Вот пример из моей практики. Двоичное дерево, к элементам которого надо было организовать еще и прямой доступ совсем по иному критерию. Завел массив указателей на элементы.

Дерево бурно строится в начале операции. Потом к нему редко могут добавляться элементы. Удаление элементов не предусмотрено, в конце операции дерево уничтожается целиком.

Ясно, что при добавлении элемента массив указателей надо переделывать. А стоит ли ? Вдруг после этого опять потребуется добавить, зачем же, спрашивается, я его переделывал ? А если не придется добавлять, а массив потребуется ?

Я массив отправил в ленивое вычисление, проще говоря, уничтожил его после добавления, присвоил указателю на него NULL и так оставил. Добавят еще раз — на здоровье. А вот когда потребуется прямой доступ — тогда он и будет перевычислен, так как произойдет обращение к нему при NULL, и он будет перевычислен.

Плюс — не делается лишняя работа (то есть не пересоздается массив на каждый чих)
Минус — когда массив понадобится, потребуется время на его вычисление.

У меня плюс перевешивал минус. Может быть наоборот.
With best regards
Pavel Dvorkin
Re[5]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 27.10.10 09:32
Оценка: +2
Здравствуйте, gandjustas, Вы писали:

T>>То есть ленивость — это по сути есть оптимизация.

G>Наоборот, энергичность — оптимизация.

С чего это вдруг? При использовании ленивости мы откладываем вычисления на максимальный срок с надеждой, что эти вычисления вообще никогда не будут выполнены. Это и есть оптимизация. Проблема здесь в том, что проявление возможных ошибок также откладывается на максимальный срок, что усложняет тестирование, обнаружение и расследование ошибок.

T>>Если производительность нас устраивает, то ленивость нафиг не нужна.

G>То есть энергичные вычисления не нужны.
Нет, энергичные вычисления проще и надежнее, но могут быть проблемы с ресурсами.
лэт ми спик фром май харт
Re[6]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.10.10 10:16
Оценка: -1 :)
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


T>>>То есть ленивость — это по сути есть оптимизация.

G>>Наоборот, энергичность — оптимизация.

T>С чего это вдруг? При использовании ленивости мы откладываем вычисления на максимальный срок с надеждой, что эти вычисления вообще никогда не будут выполнены. Это и есть оптимизация.

Снова неверный вывод. Потому что поддержка ленивости очень дорого обходится по памяти. Это тот самый tradeoff, который как раз не ведет к уменьшению потребления ресурсов.

T>Проблема здесь в том, что проявление возможных ошибок также откладывается на максимальный срок, что усложняет тестирование, обнаружение и расследование ошибок.

Вот это я совсем не понял. Если ты неуверен что функция у тебя работает правильно, то напиши тест.

T>>>Если производительность нас устраивает, то ленивость нафиг не нужна.

G>>То есть энергичные вычисления не нужны.
T>Нет, энергичные вычисления проще и надежнее, но могут быть проблемы с ресурсами.

Не в ресурсах дело, откладывание вычислений небесплатно достается. Надо замыкания таскать итп.

Но кода у тебя есть ленивые вычисления ты вполне можешь принятие решения о необходимости вычисления перенести туда где достаточно данных. Вот именно тут и получается оптимизация, иногда очень значительная.

Хороший пример это Linq.
Вот есть у тебя приложение, где по всем канонам сделана архитектура, разделены слои итп.
И у тебя есть в DAL метод, получающий данные списком, потом эти данные как-то обрабатываются в BL, и отображаются в PL. Но тут внезапно понадобилось в UI добавить разбивку по страницам с сортировкой (чисто для целей UI).
Если тебя данные из базы вытаскиваются энергично, те прямо в DAL, то тебе придется параметры сортировки передавать из PL через BL в DAL, а если у тебя ленивая выборка (IQueryable), то ты просто вызываешь OrderBy, Skip и Take.
Причем учитывая что сортировка выполняется в БД это дает немалый выйгрыш в скорости.

Аналогично в алгоритмах, связанных с поиском решения, можно в одном методе строить все дерево решений, а в другом нагладывать предикаты, отсекая лишние ветви без прохода по всему дереву каждый раз (а оно может быть вообе говоря бесконечным). В энергичном случае надо отбрасывать ветви в момент генерации, а для этого в генератор решений надо передавать все предикаты или параметры для них.
Re[4]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.10.10 10:34
Оценка: 1 (1)
Здравствуйте, Tom, Вы писали:

Tom>>>1. Не известен момент в который будет произведено вычисление

G>>Зачем? Оно ведь может быть и не произведено.
Tom>Так и не ленивое может быть не произведено.
Tom>Надо — вычисляй, не надо — не вычисляй.
Tom>Зачем делать нечто странное под названием ленивое
Ленивое может быть вычислено настолько, насколько необходимо для продолжения внешних вычислений.

Tom>>>2. Не известен поток

Tom>>>3. Не известен call stack
G>>Более того, ленивое вычисление может вообще не процессором выполняться.
Tom>Может, наверное так же как и не ленивое...
Но тогда у рантайма нет возможности соптимизировать вычисления (например батчить).

Tom>>>4. При возникновении ошибки невозможно предсказать поведение системы

G>>При отсутствии сайд-эффектов с точки зрения программы предсказать поведение вполне можно, так как ошибка может быть выкинута по месту обращения.
Tom>Как можно предсказать поведение если call stack не известен?
А в чем проблема неизвестности callstack? Как таковой стек вызовов может отсутствовать в программе при активном использовании асинхронности.

Tom>>>Ну и KISS ленивые вычисления явно нарушают.

G>>Как раз наоборот. См аппликативный и нормальный порядок редукции.
Tom>Давай раз уже пользуешься терминами — определение их.
Нормальный порядок редукции — раскрытие сначала внешних термов, аппликативный — раскрытие внутренних.
Нормальных порядок редукции соответствует ленивым вычислениям, аппликативный — энергичным.
Есть теорема, которая говорит что если выражение может быть редуцировано (вычислено) хоть как-нибудь, то оно может быть вычислено используя нормальный порядок редукции.

Tom>>>В общем если вдруг вам нужны ленивые вычисления — нужно 10 раз подумать почему. Почему вы не можете явно их выполнить в вполне детерминированные момент времени.

G>>Я бы сказал наоборот. Лучше использовать ленивые, пока вам однозначно не станут нужны энергичные вычисления.
Tom>А я бы сказал ровно наоборот.

G>>Есть целых три НО:

G>>1)Должна быть поддержка языка для ленивых вычислений (в C# её фактически нет), кроме Linq
G>>2)Должны отсутствовать наблюдаемые сайд-эффекты в вычислениях
G>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз
Tom>Как всё сложно И после этого ты будешь говорить что ленивые вычисления — более правильная парадигма чем "энергичные"?
В "правильных" языках — да. В C# — неочень.

G>>В C# всех трех условий нету, поэтому к ленивости надо относиться осторожно.

Tom>С этим полностью согласен

Tom>Вообще всё мной описанное относится исключительно к C#, разговор про функциональные языки мы тут не ведём, о них отдельная пестня

Ну так ты сформулировал претензии безотносительно языка.
Re: В чем полезность ленивых вычислений
От: matumba  
Дата: 24.10.10 22:00
Оценка: -1
Здравствуйте, Аноним, Вы писали:

А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


Например, где сложный объект состоит из маленьких, но все они не нужны сразу. Типа Settings, которые могут содержать габариты окна "About" (для восстановления), но которые (габариты) читаются раз в сто лет — их отложенная загрузка поможет быстрее стартовать приложение.
Или там, где есть вероятность отброса результата (в играх).
Re[5]: В чем полезность ленивых вычислений
От: _FRED_ Черногория
Дата: 25.10.10 05:25
Оценка: +1
Здравствуйте, hardcase, Вы писали:

G>>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз

_FR>>"Должна быть" и для итераторов?
H>У них по идее есть Reset(), правда не помню чтобы им когда-либо пользовались...

Если мне не изменяет склероз, то Reset() из реализации ленивых итераторов делают throw new NotSupportedException(); Да и не имеют никакого отношения к запоминанию: скорее, к забыванию
Help will always be given at Hogwarts to those who ask for it.
Re[4]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.10.10 06:02
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, gandjustas, Вы писали:


G>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз


_FR>"Должна быть" и для итераторов?


Итераторы как раз обладают наблюдаемыми побочными эффектами, так что ленивости для них быть не должно в принципе.
Re[9]: В чем полезность ленивых вычислений
От: _FRED_ Черногория
Дата: 25.10.10 06:27
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>>>>>>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз

_FR>>>>>>"Должна быть" и для итераторов?
G>>>>>Итераторы как раз обладают наблюдаемыми побочными эффектами, так что ленивости для них быть не должно в принципе.
_FR>>>>То есть и yield return "не должно быть в принципе"?
G>>>Как с yield никаких проблем нету. yield сам по себе никаких побочных эффектов не имеет. а вот использование IEnumerator еще как имеет.
_FR>>Не понял yield же создаёт ни что иное, как нечто ленивое. Причем "без запоминания". Почему же "нету проблем"?
_FR>>И в чём смысл разделять yield и IEnumerator?
_FR>>    static IEnumerator M() {
_FR>>      yield return 1;
_FR>>    }

_FR>>Может, имеет смысл описать подробнее, какие проблемы даёт "использование IEnumerator" при том, что "с yield никаких проблем нету"?

G>IEnumerator — объект с состоянием, прицепить к нему ленивость никак не выйдет.

G>Весь LINQ и yield создает ленивую коллекцию (без запоминания), что может приводить к проблемам.
G>Например я один раз напоролся и долго не мог понять что происходит:
G>
G>var parameters = someSeq.Select(e => Expression.Parameter(...));
G>var l = Expression.Lambda(Expression.Block(parameters,...), parameters.ToArray());
G>

G>Отладчик показывал одинаковые параметры, хотя метод Compile ругался что переменные внутри блока не найдены.

Так в чём всё-таки на ваш взгляд проблема-то? Сейчас вы сказали, что "yield создает ленивую коллекцию (без запоминания), что может приводить к проблемам", а постом ранее — "с yield никаких проблем нету" Как это нужно понять?
Help will always be given at Hogwarts to those who ask for it.
Re[12]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.10.10 06:48
Оценка: :)
Здравствуйте, _FRED_, Вы писали:

G>>У yield (и Linq) таких проблем нет, но есть проблема в отсутствии запоминания.


_FR>Ну так я с самого начала и спрашивал. Если "запоминания" нету, значит нужно быть очень осторожным. Об этом было написано тут
Автор: gandjustas
Дата: 25.10.10
. Получается и к yield нужно быть таким же осторожным, верно
Автор: _FRED_
Дата: 25.10.10
: "ленивости для них быть не должно в принципе"?


_FR>А зачем тогда нужен yield return тогда (в существующей реализации без запоминания)? Затем же, зачем и goto? Если к его результатам нужно относиться осторожно, то зачем напрягаться?


Вообще ниче не понял. Ты что сказать хочешь?
Re: В чем полезность ленивых вычислений
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.10.10 06:49
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.

В тех случаях, когда тебе нужен потенциально бесконечный источник данных.
В конкретной задаче бесконечных переборов не бывает. Но бывают конкретные задачи, построенные из абстрактных кирпичей.
И вот в этих абстрактных кирпичах бывает удобно иметь бесконечные последовательности (или, к примеру, деревья).
Например, можно написать функцию Fibonacci(), которая будет возвращать IEnumerable<int>, и работать с ней при анализе ряда Фибоначчи. Понятно, что обращение Fibonacci().ToArray() гарантированно упадёт; но в практических случаях перебор ограничивается где-нибудь ещё. И это заведомо удобнее, чем писать функцию Fibonacci(length), которая возвращает массив заданной длины — в приложении может потребоваться остановить алгоритм по каким-то другим критериям.

Примеры типа Fibonacci выглядят не очень убедительно потому, что код самой функции очень маленький, и кажется что всегда можно вставить его по месту использования. Но в жизни могут встретиться значительно более интересные случаи, в которых повторное использование будет более важным.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: В чем полезность ленивых вычислений
От: Tom Россия http://www.RSDN.ru
Дата: 25.10.10 09:44
Оценка: +1
Tom>>1. Не известен момент в который будет произведено вычисление
G>Зачем? Оно ведь может быть и не произведено.
Так и не ленивое может быть не произведено.
Надо — вычисляй, не надо — не вычисляй.
Зачем делать нечто странное под названием ленивое

Tom>>2. Не известен поток

Tom>>3. Не известен call stack
G>Более того, ленивое вычисление может вообще не процессором выполняться.
Может, наверное так же как и не ленивое...

Tom>>4. При возникновении ошибки невозможно предсказать поведение системы

G>При отсутствии сайд-эффектов с точки зрения программы предсказать поведение вполне можно, так как ошибка может быть выкинута по месту обращения.
Как можно предсказать поведение если call stack не известен?

Tom>>Ну и KISS ленивые вычисления явно нарушают.

G>Как раз наоборот. См аппликативный и нормальный порядок редукции.
Давай раз уже пользуешься терминами — определение их.

Tom>>В общем если вдруг вам нужны ленивые вычисления — нужно 10 раз подумать почему. Почему вы не можете явно их выполнить в вполне детерминированные момент времени.

G>Я бы сказал наоборот. Лучше использовать ленивые, пока вам однозначно не станут нужны энергичные вычисления.
А я бы сказал ровно наоборот.

G>Есть целых три НО:

G>1)Должна быть поддержка языка для ленивых вычислений (в C# её фактически нет), кроме Linq
G>2)Должны отсутствовать наблюдаемые сайд-эффекты в вычислениях
G>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз
Как всё сложно И после этого ты будешь говорить что ленивые вычисления — более правильная парадигма чем "энергичные"?

G>В C# всех трех условий нету, поэтому к ленивости надо относиться осторожно.

С этим полностью согласен

Вообще всё мной описанное относится исключительно к C#, разговор про функциональные языки мы тут не ведём, о них отдельная пестня
Народная мудрось
всем все никому ничего(с).
Re: В чем полезность ленивых вычислений
От: Undying Россия  
Дата: 26.10.10 11:24
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


Наиболее полезное использование ленивого вычисления этого автоматический кэш, который при обращении к нему проверяет изменились ли входы и если изменились, то пересчитывает значение, иначе возвращает кэшированное. Проблемы связанные с рассинхронизацией благодаря этому решению исчезают в принципе.
Re[2]: В чем полезность ленивых вычислений
От: Аноним  
Дата: 26.10.10 15:14
Оценка: +1
Здравствуйте, Undying, Вы писали:

U>Здравствуйте, Аноним, Вы писали:


А>>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


U>Наиболее полезное использование ленивого вычисления этого автоматический кэш, который при обращении к нему проверяет изменились ли входы и если изменились, то пересчитывает значение, иначе возвращает кэшированное. Проблемы связанные с рассинхронизацией благодаря этому решению исчезают в принципе.


Можно пример в виде кода , не совсем понятно что значит кэш коллекции и то что ее состояние не изменилось ? Откуда оно узнает о том что состояние объекта не менялось ,?
Re[4]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.10.10 21:19
Оценка: :)
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


G>>Это вообще говоря фигня. Ленивость позволяет наиболее просто записывать многие алгоритмы.

G>>Например можно построить дерево решений, полное дерево решений, оно все равно ленивое и реально будет отсутствовать в памяти, а потом методом ветвей и границ отсекать ненужные решения.

T>То есть ленивость — это по сути есть оптимизация.

Наоборот, энергичность — оптимизация.

T>Если производительность нас устраивает, то ленивость нафиг не нужна.

То есть энергичные вычисления не нужны.

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

Ты сделал неправильную посылку. Поменяй в своем сообщении ленивость на энергичность, так будет правильнее, и посмеемся вместе.
Re[7]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 27.10.10 10:38
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

T>>С чего это вдруг? При использовании ленивости мы откладываем вычисления на максимальный срок с надеждой, что эти вычисления вообще никогда не будут выполнены. Это и есть оптимизация.

G>Снова неверный вывод. Потому что поддержка ленивости очень дорого обходится по памяти. Это тот самый tradeoff, который как раз не ведет к уменьшению потребления ресурсов.

Ну и что тут такого? Просто в данном случае оптимизация не работает.

T>>Проблема здесь в том, что проявление возможных ошибок также откладывается на максимальный срок, что усложняет тестирование, обнаружение и расследование ошибок.

G>Вот это я совсем не понял. Если ты неуверен что функция у тебя работает правильно, то напиши тест.

Может тогда и статическая типизация тоже не нужна, тесты же есть?
Тесты не панацея. Полного покрытия не добьешься, ошибки могут быть интеграционного характера, могут быть связаны с "неидеальностью окружения", ошибка может быть в инсталлере, который недоинсталлировал что-нибудь, или инсталлировал, да не так. Короче говоря, причин которые не ловятся юниттестами может быть миллион.

T>>>>Если производительность нас устраивает, то ленивость нафиг не нужна.

G>>>То есть энергичные вычисления не нужны.
T>>Нет, энергичные вычисления проще и надежнее, но могут быть проблемы с ресурсами.
G>Не в ресурсах дело, откладывание вычислений небесплатно достается. Надо замыкания таскать итп.

Редко когда оптимизация дается бесплатно. Обычно приходится чем-то жертвовать. Оптимизация работает, когда бенефитов больше, чем жертв.

G>Но кода у тебя есть ленивые вычисления ты вполне можешь принятие решения о необходимости вычисления перенести туда где достаточно данных. Вот именно тут и получается оптимизация, иногда очень значительная.

Ну да. Я об этом и говорю.
лэт ми спик фром май харт
Re[8]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.10.10 11:36
Оценка: -1
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, Mystic, Вы писали:


M>>Здравствуйте, mrTwister, Вы писали:


T>>>Во-первых, не всегда, во-вторых, даже если оптимизация выполняется автоматически, мы все равно имеем проблемы с поздним обнаружением ошибок.


M>>После оптимизации код становится сложнее, и ошибки исправлять сложнее. Но ничего такого кошмарного не видно. Но откуда проблемы с "поздним обнаружением ошибок"? В любом случае ошибку мы ловим в момент использования неправильных данных, а не в момент генерации неправильных данных


T>Только этот момент наступает по-разному. Допустим, у нас есть приложение, которое использует набор модулей с динамическим связыванием. Допустим, при деплойменте мы забыли продеплоить один из модулей. В случае с энергичной загрузкой модулей мы узнаем об ошибке сразу же, при старте приложения. В случае с ленивой загрузкой, мы узнаем о проблеме только когда отсутствующий модуль реально понадобится, а это может произойти совсем не скоро, в очень редком сценарии.


Для прикола: .NET грузит сборки в момент первого обращения к типу. Например обращаясь к сборке глубоко внутри метода загрузка произойдет только при вызове этого метода. Соответственно не вызываясь он может не вызвать ошибку в случае отсутствия сборки.
И это при вполне энергичном поведении.

Не путай проблемы среды исполнения и ленивости.
Re[4]: В чем полезность ленивых вычислений
От: Аноним  
Дата: 27.10.10 15:37
Оценка: +1
Здравствуйте, Undying, Вы писали:

U>Здравствуйте, Аноним, Вы писали:


А>>Можно пример в виде кода , не совсем понятно что значит кэш коллекции и то что ее состояние не изменилось ? Откуда оно узнает о том что состояние объекта не менялось ,?


U>Простейший пример:


U>
U>    readonly RawCache<Bitmap> mapImageCache;
U>    Bitmap mapImage
U>    {
U>      get { return mapImageCache.Result; }
U>    }

U>    public MapImage(IMapModule mapModule)
U>    {
U>      this.mapImageCache = new Cache<Bitmap, Size>(
U>        delegate(Size imageSize)
U>        {
U>          return DrawingHlp.SafeCreateBitmap(imageSize.Width, imageSize.Height);
U>        },
U>        delegate { return mapPainter.ClientBounds.Size; }
U>      );
U>    }
U>


U>При вызове mapImage кэш проверяет совпадает ли текущее значение второго делегата (ClientBounds.Size) с запомненным, если да, то возвращает запомненное изображение, если нет, то вызывает первый делегат и изображение пересоздает.


Ну это обычный кэш, ленивости тут помоему нет.
Re[11]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 28.10.10 05:16
Оценка: +1
Здравствуйте, gandjustas, Вы писали:


G>>>Покажешь адекватный код где ленивость с запоминанием усложняет поиск ошибки?

T>>Представь себе IoC контейнер, описывающий набор singleton объектов. Объекты в контейнере могут создаваться энергично (при создании контейнера), либо лениво (при запросе конкретного объекта). При энергичном создании объектов ошибка в конфигурации контейнера проявится сразу, а при ленивом проявится только потом когда-нибудь.
G>Энергично нельзя создавать объекты в контейнере, потому что на момент регистрации типа могут еще не присутствовать все зависимости.
Не понял, при чем тут момент регистрации типа? В момент регистрации происходит описание типа контейнера, а не экземпляра контейнера. Чувствуешь разницу? Это все равно, что если бы ты писал class A{} и у тебя тут же бы создавался экземляр класса А. Бред. А если надо несколько экземпляров?

G>Зато можно валидировать всю конфигурацию, что все зависимости таки будут разрешены.

Теоретически можно. Но это дополнительный функционал, которым должен обладать контейнер. И что примечательно, ни один из доступных плд .NET контейнеров промышленного качества не обладает подобным функционалом.

Вообще, твое замечание по поводу того, что с поздним обнаружением ошибок надо бороться путем предварительной валидации программы — это конечно классно и офигенно. Это ведь серебряная пуля! Программа стартует и проверяет сама себя на отсутствие всех ошибок. Если находит хотябы одну ошибку, то тут завершается с багрепортом. Тестеры вообще не нужны будут!, их можно будет уволить нафиг (ведь программа сама себя тестирует). И как же я сам до этого не догадался раньше ?!?!

G>Пример — низачот, давай дальше.

Нет, мы с этим еще не закончили

T>>Общего случая нет.

G>Есть.
И что это за общий случай?

T>>Есть, случаи когда ленивость существенно экономит ресурсы, и реже наоборот.

G>А есть случаи когда черезмерно ленивая программа падает с OOM.

T>>Какой локальный результат?

G>Локальный результат в оптимизации для ленивых рекурсивных структур.
С чего ты взял? Учитывая то, в каком разделе мы находимся, я имел ввиду прежде всего применение ленивости для ускорения доступа к СУБД и ускорения старта программы (либо частей программы), как наиболее распространенные случаи использования ленивости в мире .NET
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
лэт ми спик фром май харт
В чем полезность ленивых вычислений
От: Аноним  
Дата: 24.10.10 07:42
Оценка:
Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.
Re: В чем полезность ленивых вычислений
От: _FRED_ Черногория
Дата: 24.10.10 08:05
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


Lazy Initialization
Help will always be given at Hogwarts to those who ask for it.
Re: В чем полезность ленивых вычислений
От: hardcase Пират http://nemerle.org
Дата: 24.10.10 09:11
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


Любой LINQ запрос в базу данных выполняется в ленивой манере: запрос выполняется тогда, когда происходит итерация по нему.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: В чем полезность ленивых вычислений
От: Tom Россия http://www.RSDN.ru
Дата: 24.10.10 09:28
Оценка:
_FR>Lazy Initialization
И?

Человек справивал в каких предметных областях/задачах оно может понадобится
Народная мудрось
всем все никому ничего(с).
Re[3]: В чем полезность ленивых вычислений
От: _FRED_ Черногория
Дата: 24.10.10 09:32
Оценка:
Здравствуйте, Tom, Вы писали:

_FR>>Lazy Initialization

Tom>И?
Tom>Человек справивал в каких предметных областях/задачах оно может понадобится

Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


Что-то не вижу, где человёк говорит о "предметных областях/задачах"

А вот "the most common scenarios" по ссылке как раз описывают "практические случаи".
Help will always be given at Hogwarts to those who ask for it.
Re: Харрисон «Введение в ФП»
От: Qbit86 Кипр
Дата: 24.10.10 09:38
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


Есть случаи, когда стратегия редукции «сначала самый глубокий редекс» приводит к бесконечным вычислениям. В то же время (если терм вообще сводится к терму в нормальной форме), стратегия «сначала самый внешний (левый) редекс» всегда завершается.

Классическим примером в нетипизированном лямбда-исчислении является применение функции x ↦ 1 к выражению (x ↦ x(x))(x ↦ x(x)).
Глаза у меня добрые, но рубашка — смирительная!
Re[2]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.10.10 04:44
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Здравствуйте, Аноним, Вы писали:


А>>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.

Tom>Примера из объектов реального мира я ещё не видел. Лично сам считаю что в 99% случаев ленивые вычисления являются проблемой дизайна.


Tom>Сами же ленивые вычисления только добавляют сложности в проекте ибо:

Tom>1. Не известен момент в который будет произведено вычисление
Зачем? Оно ведь может быть и не произведено.

Tom>2. Не известен поток

Tom>3. Не известен call stack
Более того, ленивое вычисление может вообще не процессором выполняться.

Tom>4. При возникновении ошибки невозможно предсказать поведение системы

При отсутствии сайд-эффектов с точки зрения программы предсказать поведение вполне можно, так как ошибка может быть выкинута по месту обращения.

Tom>Ну и KISS ленивые вычисления явно нарушают.

Как раз наоборот. См аппликативный и нормальный порядок редукции.

Tom>В общем если вдруг вам нужны ленивые вычисления — нужно 10 раз подумать почему. Почему вы не можете явно их выполнить в вполне детерминированные момент времени.

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

Есть целых три НО:
1)Должна быть поддержка языка для ленивых вычислений (в C# её фактически нет), кроме Linq
2)Должны отсутствовать наблюдаемые сайд-эффекты в вычислениях
3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз

В C# всех трех условий нету, поэтому к ленивости надо относиться осторожно.
Re[3]: В чем полезность ленивых вычислений
От: _FRED_ Черногория
Дата: 25.10.10 04:51
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз


"Должна быть" и для итераторов?
Help will always be given at Hogwarts to those who ask for it.
Re[4]: В чем полезность ленивых вычислений
От: hardcase Пират http://nemerle.org
Дата: 25.10.10 05:18
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, gandjustas, Вы писали:


G>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз


_FR>"Должна быть" и для итераторов?


У них по идее есть Reset(), правда не помню чтобы им когда-либо пользовались...
/* иЗвиНите зА неРовнЫй поЧерК */
Re: В чем полезность ленивых вычислений
От: Undying Россия  
Дата: 25.10.10 05:37
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


В плане производительности полезны, если нужны тяжелые промежуточные объекты. Ленивость в таких задачах позволяет получить приличный выигрыш по пиковой памяти и существенный в производительности (десятки процентов). Но если промежуточные объекты легкие, тогда смысла использовать ленивость нет, производительность обычно наоборот хуже.
Re[5]: В чем полезность ленивых вычислений
От: _FRED_ Черногория
Дата: 25.10.10 06:06
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз

_FR>>"Должна быть" и для итераторов?
G>Итераторы как раз обладают наблюдаемыми побочными эффектами, так что ленивости для них быть не должно в принципе.

То есть и yield return "не должно быть в принципе"?
Help will always be given at Hogwarts to those who ask for it.
Re[6]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.10.10 06:08
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, gandjustas, Вы писали:


G>>>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз

_FR>>>"Должна быть" и для итераторов?
G>>Итераторы как раз обладают наблюдаемыми побочными эффектами, так что ленивости для них быть не должно в принципе.

_FR>То есть и yield return "не должно быть в принципе"?


Как с yield никаких проблем нету. yield сам по себе никаких побочных эффектов не имеет. а вот использование IEnumerator еще как имеет.
Re[7]: В чем полезность ленивых вычислений
От: _FRED_ Черногория
Дата: 25.10.10 06:14
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз

_FR>>>>"Должна быть" и для итераторов?
G>>>Итераторы как раз обладают наблюдаемыми побочными эффектами, так что ленивости для них быть не должно в принципе.
_FR>>То есть и yield return "не должно быть в принципе"?

G>Как с yield никаких проблем нету. yield сам по себе никаких побочных эффектов не имеет. а вот использование IEnumerator еще как имеет.


Не понял yield же создаёт ни что иное, как нечто ленивое. Причем "без запоминания". Почему же "нету проблем"?

И в чём смысл разделять yield и IEnumerator?

    static IEnumerator M() {
      yield return 1;
    }


Может, имеет смысл описать подробнее, какие проблемы даёт "использование IEnumerator" при том, что "с yield никаких проблем нету"?
Help will always be given at Hogwarts to those who ask for it.
Re[2]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.10.10 06:16
Оценка:
Здравствуйте, Undying, Вы писали:

U>Здравствуйте, Аноним, Вы писали:


А>>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


U>В плане производительности полезны, если нужны тяжелые промежуточные объекты. Ленивость в таких задачах позволяет получить приличный выигрыш по пиковой памяти и существенный в производительности (десятки процентов). Но если промежуточные объекты легкие, тогда смысла использовать ленивость нет, производительность обычно наоборот хуже.


Это вообще говоря фигня. Ленивость позволяет наиболее просто записывать многие алгоритмы.
Например можно построить дерево решений, полное дерево решений, оно все равно ленивое и реально будет отсутствовать в памяти, а потом методом ветвей и границ отсекать ненужные решения.

В энергичном языке придется передавать внутрь вычислителя контекст, который внутри будет проверять отсекать текущую ветку или продолжать поиск. Или придется вручную эмулировать ленивость с запоминанием.

Ленивость дает максимальную свободу декомпозиции задач и композиции решений.
Re[8]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.10.10 06:23
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, gandjustas, Вы писали:


G>>>>>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз

_FR>>>>>"Должна быть" и для итераторов?
G>>>>Итераторы как раз обладают наблюдаемыми побочными эффектами, так что ленивости для них быть не должно в принципе.
_FR>>>То есть и yield return "не должно быть в принципе"?

G>>Как с yield никаких проблем нету. yield сам по себе никаких побочных эффектов не имеет. а вот использование IEnumerator еще как имеет.


_FR>Не понял yield же создаёт ни что иное, как нечто ленивое. Причем "без запоминания". Почему же "нету проблем"?


_FR>И в чём смысл разделять yield и IEnumerator?


_FR>
_FR>    static IEnumerator M() {
_FR>      yield return 1;
_FR>    }
_FR>


_FR>Может, имеет смысл описать подробнее, какие проблемы даёт "использование IEnumerator" при том, что "с yield никаких проблем нету"?


IEnumerator — объект с состоянием, прицепить к нему ленивость никак не выйдет.
Весь LINQ и yield создает ленивую коллекцию (без запоминания), что может приводить к проблемам.
Например я один раз напоролся и долго не мог понять что происходит:
var parameters = someSeq.Select(e => Expression.Parameter(...));
var l = Expression.Lambda(Expression.Block(parameters,...), parameters.ToArray());

Отладчик показывал одинаковые параметры, хотя метод Compile ругался что переменные внутри блока не найдены.
Re[10]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.10.10 06:33
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, gandjustas, Вы писали:


G>>>>>>>>3)Ленивость должна быть с запоминанием, те если ленивое выражение было вычислено, но оно не должно вычисляться второй раз

_FR>>>>>>>"Должна быть" и для итераторов?
G>>>>>>Итераторы как раз обладают наблюдаемыми побочными эффектами, так что ленивости для них быть не должно в принципе.
_FR>>>>>То есть и yield return "не должно быть в принципе"?
G>>>>Как с yield никаких проблем нету. yield сам по себе никаких побочных эффектов не имеет. а вот использование IEnumerator еще как имеет.
_FR>>>Не понял yield же создаёт ни что иное, как нечто ленивое. Причем "без запоминания". Почему же "нету проблем"?
_FR>>>И в чём смысл разделять yield и IEnumerator?
_FR>
_FR>>>    static IEnumerator M() {
_FR>>>      yield return 1;
_FR>>>    }
_FR>

_FR>>>Может, имеет смысл описать подробнее, какие проблемы даёт "использование IEnumerator" при том, что "с yield никаких проблем нету"?

G>>IEnumerator — объект с состоянием, прицепить к нему ленивость никак не выйдет.

G>>Весь LINQ и yield создает ленивую коллекцию (без запоминания), что может приводить к проблемам.
G>>Например я один раз напоролся и долго не мог понять что происходит:
G>>
G>>var parameters = someSeq.Select(e => Expression.Parameter(...));
G>>var l = Expression.Lambda(Expression.Block(parameters,...), parameters.ToArray());
G>>

G>>Отладчик показывал одинаковые параметры, хотя метод Compile ругался что переменные внутри блока не найдены.

_FR>Так в чём всё-таки на ваш взгляд проблема-то? Сейчас вы сказали, что "yield создает ленивую коллекцию (без запоминания), что может приводить к проблемам", а постом ранее — "с yield никаких проблем нету" Как это нужно понять?

Это не нужно понимать. Я сначала подумал про IEnumerator, для него проблема в состоянии и ленивость ему не прицепишь. У yield (и Linq) таких проблем нет, но есть проблема в отсутствии запоминания.
Re[11]: В чем полезность ленивых вычислений
От: _FRED_ Черногория
Дата: 25.10.10 06:41
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Это не нужно понимать. Я сначала подумал про IEnumerator, для него проблема в состоянии и ленивость ему не прицепишь.


А как к этому следует относиться?

G>У yield (и Linq) таких проблем нет, но есть проблема в отсутствии запоминания.


Ну так я с самого начала и спрашивал. Если "запоминания" нету, значит нужно быть очень осторожным. Об этом было написано тут
Автор: gandjustas
Дата: 25.10.10
. Получается и к yield нужно быть таким же осторожным, верно
Автор: _FRED_
Дата: 25.10.10
: "ленивости для них быть не должно в принципе"?

А зачем тогда нужен yield return тогда (в существующей реализации без запоминания)? Затем же, зачем и goto? Если к его результатам нужно относиться осторожно, то зачем напрягаться?
Help will always be given at Hogwarts to those who ask for it.
Re[13]: В чем полезность ленивых вычислений
От: _FRED_ Черногория
Дата: 25.10.10 06:59
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>У yield (и Linq) таких проблем нет, но есть проблема в отсутствии запоминания.

_FR>>Ну так я с самого начала и спрашивал. Если "запоминания" нету, значит нужно быть очень осторожным. Об этом было написано тут
Автор: gandjustas
Дата: 25.10.10
. Получается и к yield нужно быть таким же осторожным, верно
Автор: _FRED_
Дата: 25.10.10
: "ленивости для них быть не должно в принципе"?

_FR>>А зачем тогда нужен yield return тогда (в существующей реализации без запоминания)? Затем же, зачем и goto? Если к его результатам нужно относиться осторожно, то зачем напрягаться?

G>Вообще ниче не понял.


"А зачем тогда нужен yield return"? — что тут не понятного? "тогда" означает "если <Ленивость должна быть с запоминанием>".

G>Ты что сказать хочешь?


Я хочу сказать, что из того, что

Ленивость должна быть с запоминанием

следует, что yield return быть не должно (ибо yield return — это ленивость без запоминания). Но следующие ответы ставят под сомнение этот вывод. Так может быть, предпосылка не верна?
Help will always be given at Hogwarts to those who ask for it.
Re[5]: В чем полезность ленивых вычислений
От: Tom Россия http://www.RSDN.ru
Дата: 25.10.10 13:18
Оценка:
G>Ленивое может быть вычислено настолько, насколько необходимо для продолжения внешних вычислений.
Это только ленивое вычисление может быть сделано настолько насколько это надо для продолжения вычислений?

Tom>>Может, наверное так же как и не ленивое...

G>Но тогда у рантайма нет возможности соптимизировать вычисления (например батчить).
Ммммм, отчасти соглашусь. Но всё таки не надо забывать о том что преждевременная оптимизация...
ну и батчить в зависимости от ситуации можно самому.
Например используя паттерн Command.

Tom>>Как можно предсказать поведение если call stack не известен?

G>А в чем проблема неизвестности callstack? Как таковой стек вызовов может отсутствовать в программе при активном использовании асинхронности.
Стек отсуствовать
А проблема простая, у callstack-а есть контекст. Например могут быть определены переменные, некоторые например могут быть ThreadStatic, может присуствовать какой то TransactionScope, у потоков могут быть различные Apartment Model, выполнение может происходить при наличии различных блокировок. Всё это может привести к непредсказуемым результатам выполнения.

Tom>>Как всё сложно И после этого ты будешь говорить что ленивые вычисления — более правильная парадигма чем "энергичные"?

G>В "правильных" языках — да. В C# — неочень.
В правильных языках side эффекты невозможны?

G>>>В C# всех трех условий нету, поэтому к ленивости надо относиться осторожно.

Tom>>С этим полностью согласен

Tom>>Вообще всё мной описанное относится исключительно к C#, разговор про функциональные языки мы тут не ведём, о них отдельная пестня

G>Ну так ты сформулировал претензии безотносительно языка.
В данном форуме C# — дефолтный язык
Народная мудрось
всем все никому ничего(с).
Re[6]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.10.10 13:56
Оценка:
Здравствуйте, Tom, Вы писали:

G>>Ленивое может быть вычислено настолько, насколько необходимо для продолжения внешних вычислений.

Tom>Это только ленивое вычисление может быть сделано настолько насколько это надо для продолжения вычислений?
Да, для энергичных вычислений ты сам должен ограничивать глубину. В языке с ленивостью можно построить дерево решений, а потом бегать по нему отсекая ненужные ветки.

Tom>>>Как можно предсказать поведение если call stack не известен?

G>>А в чем проблема неизвестности callstack? Как таковой стек вызовов может отсутствовать в программе при активном использовании асинхронности.
Tom>Стек отсуствовать
Tom>А проблема простая, у callstack-а есть контекст. Например могут быть определены переменные, некоторые например могут быть ThreadStatic, может присуствовать какой то TransactionScope, у потоков могут быть различные Apartment Model, выполнение может происходить при наличии различных блокировок. Всё это может привести к непредсказуемым результатам выполнения.
Если вычисления функционально чисты, то нет. А ленивость с сайд-эффектами плохо сочетается, это всем вроде бы известно.

Tom>>>Как всё сложно И после этого ты будешь говорить что ленивые вычисления — более правильная парадигма чем "энергичные"?

G>>В "правильных" языках — да. В C# — неочень.
Tom>В правильных языках side эффекты невозможны?
Возможны, но они присутствуют там явно.
Re[2]: В чем полезность ленивых вычислений
От: Aviator  
Дата: 26.10.10 14:20
Оценка:
Здравствуйте, dilmah, Вы писали:

А>>Приведите пожалуйста пример в каком практическом случае эффективно использовать ленивое вычисление.


D>практическая польза в том, что ты можешь писать более простой и понятный код, не волнуясь об оптимизации, зная что она произойдет автоматически.

1. Ага будет очень понятно когда при обращению к проперти из ГУИ получишь какой-нибудь socket exception
2. Можно наоборот получить сильно неоптимальный код
Re[3]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 26.10.10 19:40
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Это вообще говоря фигня. Ленивость позволяет наиболее просто записывать многие алгоритмы.

G>Например можно построить дерево решений, полное дерево решений, оно все равно ленивое и реально будет отсутствовать в памяти, а потом методом ветвей и границ отсекать ненужные решения.

То есть ленивость — это по сути есть оптимизация. Если производительность нас устраивает, то ленивость нафиг не нужна. Если же производительность не устраивает, то ленивость — это один из способов оптимизации, который, как и любая другая оптимизация, усложняет оригинальное (то есть без оптимизаций) решение. Короче говоря, тут работают все остальные широко известные правила применения оптимизаций.
лэт ми спик фром май харт
Re[3]: В чем полезность ленивых вычислений
От: Undying Россия  
Дата: 27.10.10 03:27
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Можно пример в виде кода , не совсем понятно что значит кэш коллекции и то что ее состояние не изменилось ? Откуда оно узнает о том что состояние объекта не менялось ,?


Простейший пример:

    readonly RawCache<Bitmap> mapImageCache;
    Bitmap mapImage
    {
      get { return mapImageCache.Result; }
    }

    public MapImage(IMapModule mapModule)
    {
      this.mapImageCache = new Cache<Bitmap, Size>(
        delegate(Size imageSize)
        {
          return DrawingHlp.SafeCreateBitmap(imageSize.Width, imageSize.Height);
        },
        delegate { return mapPainter.ClientBounds.Size; }
      );
    }


При вызове mapImage кэш проверяет совпадает ли текущее значение второго делегата (ClientBounds.Size) с запомненным, если да, то возвращает запомненное изображение, если нет, то вызывает первый делегат и изображение пересоздает.
Re[4]: В чем полезность ленивых вычислений
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 27.10.10 09:57
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Если же производительность не устраивает, то ленивость — это один из способов оптимизации, который, как и любая другая оптимизация, усложняет оригинальное (то есть без оптимизаций) решение.


Есть небольшой нюанс, который состоит в том, что решение может требовать бесконечного количества времени/ресурсов. Т. е. изначально решение нерабочее. Но ленивость может сделать его рабочим. Второй нюанс в том, что эта оптимизация выполняется автоматически средой, а не руками.
Re[5]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 27.10.10 10:41
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Есть небольшой нюанс, который состоит в том, что решение может требовать бесконечного количества времени/ресурсов. Т. е. изначально решение нерабочее. Но ленивость может сделать его рабочим.

Согласен.

M>Второй нюанс в том, что эта оптимизация выполняется автоматически средой, а не руками.

Во-первых, не всегда, во-вторых, даже если оптимизация выполняется автоматически, мы все равно имеем проблемы с поздним обнаружением ошибок.
лэт ми спик фром май харт
Re[6]: В чем полезность ленивых вычислений
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 27.10.10 10:52
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Во-первых, не всегда, во-вторых, даже если оптимизация выполняется автоматически, мы все равно имеем проблемы с поздним обнаружением ошибок.


После оптимизации код становится сложнее, и ошибки исправлять сложнее. Но ничего такого кошмарного не видно. Но откуда проблемы с "поздним обнаружением ошибок"? В любом случае ошибку мы ловим в момент использования неправильных данных, а не в момент генерации неправильных данных
Re[7]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 27.10.10 11:04
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Здравствуйте, mrTwister, Вы писали:


T>>Во-первых, не всегда, во-вторых, даже если оптимизация выполняется автоматически, мы все равно имеем проблемы с поздним обнаружением ошибок.


M>После оптимизации код становится сложнее, и ошибки исправлять сложнее. Но ничего такого кошмарного не видно. Но откуда проблемы с "поздним обнаружением ошибок"? В любом случае ошибку мы ловим в момент использования неправильных данных, а не в момент генерации неправильных данных


Только этот момент наступает по-разному. Допустим, у нас есть приложение, которое использует набор модулей с динамическим связыванием. Допустим, при деплойменте мы забыли продеплоить один из модулей. В случае с энергичной загрузкой модулей мы узнаем об ошибке сразу же, при старте приложения. В случае с ленивой загрузкой, мы узнаем о проблеме только когда отсутствующий модуль реально понадобится, а это может произойти совсем не скоро, в очень редком сценарии.
лэт ми спик фром май харт
Re[8]: В чем полезность ленивых вычислений
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 27.10.10 11:12
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Только этот момент наступает по-разному. Допустим, у нас есть приложение, которое использует набор модулей с динамическим связыванием. Допустим, при деплойменте мы забыли продеплоить один из модулей. В случае с энергичной загрузкой модулей мы узнаем об ошибке сразу же, при старте приложения. В случае с ленивой загрузкой, мы узнаем о проблеме только когда отсутствующий модуль реально понадобится, а это может произойти совсем не скоро, в очень редком сценарии.


Только при чем тут ленивые вычисления? Тут при вызове функции есть явный побочный эффект. Так можно дойти до того, что при вызов Console.WriteLine вообще не должен вызываться, потому что возвращаемого значения нет (нигде не используется)?
Re[8]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.10.10 11:32
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


T>>>С чего это вдруг? При использовании ленивости мы откладываем вычисления на максимальный срок с надеждой, что эти вычисления вообще никогда не будут выполнены. Это и есть оптимизация.

G>>Снова неверный вывод. Потому что поддержка ленивости очень дорого обходится по памяти. Это тот самый tradeoff, который как раз не ведет к уменьшению потребления ресурсов.

T>Ну и что тут такого? Просто в данном случае оптимизация не работает.


Значит это не оптимизация.

T>>>Проблема здесь в том, что проявление возможных ошибок также откладывается на максимальный срок, что усложняет тестирование, обнаружение и расследование ошибок.

G>>Вот это я совсем не понял. Если ты неуверен что функция у тебя работает правильно, то напиши тест.

T>Может тогда и статическая типизация тоже не нужна, тесты же есть?

T>Тесты не панацея. Полного покрытия не добьешься, ошибки могут быть интеграционного характера, могут быть связаны с "неидеальностью окружения", ошибка может быть в инсталлере, который недоинсталлировал что-нибудь, или инсталлировал, да не так. Короче говоря, причин которые не ловятся юниттестами может быть миллион.
Круто, что из этого относится к ленивым вычислениям?
Покажешь адекватный код где ленивость с запоминанием усложняет поиск ошибки?

T>>>>>Если производительность нас устраивает, то ленивость нафиг не нужна.

G>>>>То есть энергичные вычисления не нужны.
T>>>Нет, энергичные вычисления проще и надежнее, но могут быть проблемы с ресурсами.
G>>Не в ресурсах дело, откладывание вычислений небесплатно достается. Надо замыкания таскать итп.
T>Редко когда оптимизация дается бесплатно. Обычно приходится чем-то жертвовать. Оптимизация работает, когда бенефитов больше, чем жертв.
Еще раз: ленивость не оптимизация, в общем случае она ведет к большему расходу ресурсов.

G>>Но кода у тебя есть ленивые вычисления ты вполне можешь принятие решения о необходимости вычисления перенести туда где достаточно данных. Вот именно тут и получается оптимизация, иногда очень значительная.

T>Ну да. Я об этом и говорю.
Нет, ты пытаешься экстраполировать локальный результат на всю ленивость, это неверно.
Re[7]: В чем полезность ленивых вычислений
От: v.a.v СССР  
Дата: 27.10.10 16:46
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Снова неверный вывод. Потому что поддержка ленивости очень дорого обходится по памяти. Это тот самый tradeoff, который как раз не ведет к уменьшению потребления ресурсов.


Почему вы так считаете? Ленивость и кеширование концепции не связанные(могут использоваться и вместе и порознь). Как конкретно ленивость увеличивает затраты памяти? Я понимаю что существуют решения, когда затраты памяти действительно возрастают. Но я не вижу закономерности.
Re[9]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 27.10.10 18:30
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Только при чем тут ленивые вычисления?

Это был пример ленивости при загрузки модулей.

M>Тут при вызове функции есть явный побочный эффект.

Клиенту этот побочный эффект совершенно прозрачен.

M>Так можно дойти до того, что при вызов Console.WriteLine вообще не должен вызываться, потому что возвращаемого значения нет (нигде не используется)?

Пример не к месту, так как Console.WriteLine имеет важный для клиента побочный эффект.
лэт ми спик фром май харт
Re[9]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 27.10.10 18:39
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Может тогда и статическая типизация тоже не нужна, тесты же есть?

T>>Тесты не панацея. Полного покрытия не добьешься, ошибки могут быть интеграционного характера, могут быть связаны с "неидеальностью окружения", ошибка может быть в инсталлере, который недоинсталлировал что-нибудь, или инсталлировал, да не так. Короче говоря, причин которые не ловятся юниттестами может быть миллион.
G>Круто, что из этого относится к ленивым вычислениям?
Все, что угодно.

G>Покажешь адекватный код где ленивость с запоминанием усложняет поиск ошибки?

Представь себе IoC контейнер, описывающий набор singleton объектов. Объекты в контейнере могут создаваться энергично (при создании контейнера), либо лениво (при запросе конкретного объекта). При энергичном создании объектов ошибка в конфигурации контейнера проявится сразу, а при ленивом проявится только потом когда-нибудь.

G>Еще раз: ленивость не оптимизация, в общем случае она ведет к большему расходу ресурсов.

Общего случая нет. Есть, случаи когда ленивость существенно экономит ресурсы, и реже наоборот.

G>Нет, ты пытаешься экстраполировать локальный результат на всю ленивость, это неверно.

Какой локальный результат?
лэт ми спик фром май харт
Re[9]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 27.10.10 18:40
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Для прикола: .NET грузит сборки в момент первого обращения к типу.

Я знаю. Это и есть оптимизация времени загрузки сборки.
лэт ми спик фром май харт
Re[10]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 27.10.10 21:14
Оценка:
Здравствуйте, mrTwister, Вы писали:

G>>Покажешь адекватный код где ленивость с запоминанием усложняет поиск ошибки?

T>Представь себе IoC контейнер, описывающий набор singleton объектов. Объекты в контейнере могут создаваться энергично (при создании контейнера), либо лениво (при запросе конкретного объекта). При энергичном создании объектов ошибка в конфигурации контейнера проявится сразу, а при ленивом проявится только потом когда-нибудь.
Энергично нельзя создавать объекты в контейнере, потому что на момент регистрации типа могут еще не присутствовать все зависимости.
Зато можно валидировать всю конфигурацию, что все зависимости таки будут разрешены.
Пример — низачот, давай дальше.

G>>Еще раз: ленивость не оптимизация, в общем случае она ведет к большему расходу ресурсов.

T>Общего случая нет.
Есть.

T>Есть, случаи когда ленивость существенно экономит ресурсы, и реже наоборот.

А есть случаи когда черезмерно ленивая программа падает с OOM.

G>>Нет, ты пытаешься экстраполировать локальный результат на всю ленивость, это неверно.

T>Какой локальный результат?
Локальный результат в оптимизации для ленивых рекурсивных структур.
Re[5]: В чем полезность ленивых вычислений
От: Undying Россия  
Дата: 28.10.10 03:27
Оценка:
Здравствуйте, Аноним, Вы писали:

U>>При вызове mapImage кэш проверяет совпадает ли текущее значение второго делегата (ClientBounds.Size) с запомненным, если да, то возвращает запомненное изображение, если нет, то вызывает первый делегат и изображение пересоздает.


А>Ну это обычный кэш, ленивости тут помоему нет.


Ленивость есть, т.к. кэш пересчитывает значение не тогда, когда произошло изменение входа, а при обращении за значением.
Re[12]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 28.10.10 07:29
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:



G>>>>Покажешь адекватный код где ленивость с запоминанием усложняет поиск ошибки?

T>>>Представь себе IoC контейнер, описывающий набор singleton объектов. Объекты в контейнере могут создаваться энергично (при создании контейнера), либо лениво (при запросе конкретного объекта). При энергичном создании объектов ошибка в конфигурации контейнера проявится сразу, а при ленивом проявится только потом когда-нибудь.
G>>Энергично нельзя создавать объекты в контейнере, потому что на момент регистрации типа могут еще не присутствовать все зависимости.
T>Не понял, при чем тут момент регистрации типа? В момент регистрации происходит описание типа контейнера, а не экземпляра контейнера. Чувствуешь разницу? Это все равно, что если бы ты писал class A{} и у тебя тут же бы создавался экземляр класса А. Бред. А если надо несколько экземпляров?
Я это знаю.
Ты описал откровенно бажный сценарий для энергичного случая, а в ленивом как раз все ОК.

G>>Пример — низачот, давай дальше.

T>Нет, мы с этим еще не закончили
А все равно низачот. Ты описал поведение бажного контейнера, который как раз будет глючить в случае энергичного получения инстансов.

T>>>Общего случая нет.

G>>Есть.
T>И что это за общий случай?
Это когда все лениво.

T>>>Есть, случаи когда ленивость существенно экономит ресурсы, и реже наоборот.

G>>А есть случаи когда черезмерно ленивая программа падает с OOM.

T>>>Какой локальный результат?

G>>Локальный результат в оптимизации для ленивых рекурсивных структур.
T>С чего ты взял? Учитывая то, в каком разделе мы находимся, я имел ввиду прежде всего применение ленивости для ускорения доступа к СУБД и ускорения старта программы (либо частей программы), как наиболее распространенные случаи использования ленивости в мире .NET
Так с этого и надо было начинать.
Re[13]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 28.10.10 18:16
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Не понял, при чем тут момент регистрации типа? В момент регистрации происходит описание типа контейнера, а не экземпляра контейнера. Чувствуешь разницу? Это все равно, что если бы ты писал class A{} и у тебя тут же бы создавался экземляр класса А. Бред. А если надо несколько экземпляров?

G>Я это знаю.
G>Ты описал откровенно бажный сценарий для энергичного случая, а в ленивом как раз все ОК.
Что-то тебя не в ту степь понесло. О ленивости или энергичности имеет смысл говорить не при описании типа, а при описании экземпляра. Тут ленивость затрудняет поиск ошибок

G>>>Пример — низачот, давай дальше.

T>>Нет, мы с этим еще не закончили
G>А все равно низачот. Ты описал поведение бажного контейнера, который как раз будет глючить в случае энергичного получения инстансов.
Не понял, какой еще "бажный" контейнер, ты вообще что имеешь ввиду? В чем "бажность" заключается?

T>>>>Общего случая нет.

G>>>Есть.
T>>И что это за общий случай?
G>Это когда все лениво.
А почему не когда все энергично?
лэт ми спик фром май харт
Re[14]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 29.10.10 06:17
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


T>>>Не понял, при чем тут момент регистрации типа? В момент регистрации происходит описание типа контейнера, а не экземпляра контейнера. Чувствуешь разницу? Это все равно, что если бы ты писал class A{} и у тебя тут же бы создавался экземляр класса А. Бред. А если надо несколько экземпляров?

G>>Я это знаю.
G>>Ты описал откровенно бажный сценарий для энергичного случая, а в ленивом как раз все ОК.
T>Что-то тебя не в ту степь понесло. О ленивости или энергичности имеет смысл говорить не при описании типа, а при описании экземпляра. Тут ленивость затрудняет поиск ошибок
Это тебя не туда понесло. Ленивость — свойство вычислений, а не типов или экземпляров.

G>>>>Пример — низачот, давай дальше.

T>>>Нет, мы с этим еще не закончили
G>>А все равно низачот. Ты описал поведение бажного контейнера, который как раз будет глючить в случае энергичного получения инстансов.
T>Не понял, какой еще "бажный" контейнер, ты вообще что имеешь ввиду? В чем "бажность" заключается?
В том что в некоторых адекватных сценариях будет падать, именно из-за энергичности вычислений.

T>>>>>Общего случая нет.

G>>>>Есть.
T>>>И что это за общий случай?
G>>Это когда все лениво.
T>А почему не когда все энергично?
Так мы же именно ленивость обсуждали.
Я и говорю что в общем случае, когда ленивость везде. Такое ведет к большему в среднем потреблению ресурсов.
Re[2]: В чем полезность ленивых вычислений
От: BulatZiganshin  
Дата: 29.10.10 11:58
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Сами же ленивые вычисления только добавляют сложности в проекте ибо:

Tom>1. Не известен момент в который будет произведено вычисление
Tom>2. Не известен поток
Tom>3. Не известен call stack
Tom>4. При возникновении ошибки невозможно предсказать поведение системы

Tom>Ну и KISS ленивые вычисления явно нарушают.


то же самое можно сказать о любой высокоуровневой концепции с точки зрения того, кто с нею незнаком. могу напомнить, что в 20-летнем давности руководстве по турбо-паскалю ООП описывался как мутная штука, которой сложно овладеть
Люди, я люблю вас! Будьте бдительны!!!
Re[15]: В чем полезность ленивых вычислений
От: mrTwister Россия  
Дата: 29.10.10 18:25
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Это тебя не туда понесло. Ленивость — свойство вычислений, а не типов или экземпляров.

Создание экземпляра — это результат вычисления, которое может быть ленивым или энергичным.

G>В том что в некоторых адекватных сценариях будет падать, именно из-за энергичности вычислений.

Что это за адекватные сценарии?

G>Я и говорю что в общем случае, когда ленивость везде. Такое ведет к большему в среднем потреблению ресурсов.

С чего это вдруг? Вон, выше по ветке Mystic заметил, что в иногда энергичность может потреблять бесконечное количество ресурсов, где ленивость будет нормально работать.
лэт ми спик фром май харт
Re[16]: В чем полезность ленивых вычислений
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 02.11.10 07:33
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


G>>Это тебя не туда понесло. Ленивость — свойство вычислений, а не типов или экземпляров.

T>Создание экземпляра — это результат вычисления, которое может быть ленивым или энергичным.
Правильно, и это не от типа зависит.

G>>В том что в некоторых адекватных сценариях будет падать, именно из-за энергичности вычислений.

T>Что это за адекватные сценарии?
Рекурсивные конструкции.

fibs = 1:1:zipWith (+) fibs (tail fibs)



G>>Я и говорю что в общем случае, когда ленивость везде. Такое ведет к большему в среднем потреблению ресурсов.

T>С чего это вдруг? Вон, выше по ветке Mystic заметил, что в иногда энергичность может потреблять бесконечное количество ресурсов, где ленивость будет нормально работать.
Это никак не связано с оптимизацией. Есть теорема которая говорит что если выражение может быть вычислено хоть как-то, то оно может быть вычислено ленивым способом.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.