Отсрочка исполнения почти всегда благо. Но бывают случаи, когда это проблема, и вы прибегаете к «выборке» (в Nhibernate), чтобы получить ее.
Знаете ли вы практические ситуации, когда ленивое вычисление может вас укусить…?
Отсрочка исполнения почти всегда благо. Но бывают случаи, когда это проблема, и вы прибегаете к «выборке» (в Nhibernate), чтобы получить ее.
Знаете ли вы практические ситуации, когда ленивое вычисление может вас укусить…?
Вы не можете выполнить сокращение (например, складку) входных данных в постоянном пространстве с помощью ленивых вычислений, поскольку отложенное вычисление каждого шага сокращения приводит к сложности линейного пространства. Вместо этого вы должны принудительно оценивать результат каждого шага сокращения, чтобы поддерживать постоянное использование пространства.
Например, хэширование файла в Haskell. Возможно, вы имеете хорошие намерения и лениво читаете входной файл по частям, добавляя каждую часть в дайджест, но за вашей спиной Haskell на самом деле создает преобразователь для каждой части, которую вы добавляете в дайджест, оставляя весь файл в памяти. эти преобразователи до тех пор, пока результирующий дайджест не будет фактически оценен. Ой!
См. последний комментарий здесь: Отложенный ввод-вывод Haskell и закрытие файлов
Ленивая оценка бесполезна в ситуациях, когда производительность критична и значение должно оцениваться всегда. В этих случаях вам лучше просто оценить значение и покончить с ним, потому что накладные расходы на ленивую оценку будут потрачены впустую.
Ленивая оценка бесполезна, если оценка может иметь побочные эффекты. Это единственная причина, и именно поэтому она есть только у чисто функциональных языков. Если у выражений могут быть побочные эффекты, которые должны происходить в определенном порядке, у вас их быть не может.
Кроме того, ленивая оценка только повышает производительность, это ее основная цель. И именно поэтому некоторые языки запрещают побочные эффекты, чтобы получить ленивую оценку для этого компромисса, еще один приятный эффект этого заключается в том, что управляющие структуры могут быть обычными функциями.
Один пример лени, вызывающей странные проблемы (случилось со мной сегодня, в Haskell):
import System.IO
main = do
content <- readFile "foo.txt"
writeFile "foo.txt" content
Это выдает следующую ошибку при компиляции и выполнении:
foo.txt: openFile: resource busy (file is locked)
Я думал, что это будет делать: открыть файл foo.txt, прочитать содержимое, снова закрыть. Затем откройте его для записи, напишите содержимое и снова закройте.
Что он на самом деле сделал: «А, немного контента. Я, наверное, прочитаю его позже, когда он нам действительно понадобится». Затем откройте «foo.txt» для записи. Начинайте писать контент... хорошо, теперь нам нужен контент. Откройте foo.txt для чтения — бац!
Я знаю, что это тривиально исправить, но это трудно найти, если вы не знаете, где искать.
Ресурсы ленивой загрузки включают в себя переход туда и обратно между запрашивающей стороной и источником для каждой загрузки. В случае с NHibernate это означает переход от приложения к базе данных (которая часто находится на другом сервере).
С каждой поездкой часто связаны накладные расходы (конечно, для NHibernate или любого другого запроса к БД).
Если вы знаете, что вам потребуются все или значительная часть данных, вам лучше получить их за один раз и понести накладные расходы только один раз.
Классический пример — когда вам нужно вывести список объектов для заполнения поля со списком (часто это будут объекты конфигурации). Ленивая загрузка будет возвращаться к базе данных каждый раз, когда вы добавляете элемент списка в поле со списком. Поскольку вы помещаете весь список в поле со списком, вы понесете много дополнительных накладных расходов на ленивую выборку каждого объекта.
Это также может быть проблемой с пользовательским интерфейсом вашей программы. Люди будут счастливы ждать 5 секунд, когда баннер отображается на экране во время загрузки приложения, но они презирают необходимость ждать 0,25 секунды, когда они что-то вводят в текстовое поле. Если время, необходимое для быстрой загрузки всех ваших данных, не так велико, вы можете подумать о том, чтобы сделать это в какой-то момент рабочего процесса, когда люди допускают задержку (например, загрузка приложения, всплывающее окно, нажатие кнопки).
Ленивая оценка бесполезна, если вы не хотите сохранять значение, просто используйте его. Но это зависит от реализации ленивого вычислителя. Некоторые системы (например, Haskell) могут сказать, будет ли значение использоваться снова. Некоторые другие не могут и могут вызывать утечки.