Когда ленивое вычисление бесполезно?

Отсрочка исполнения почти всегда благо. Но бывают случаи, когда это проблема, и вы прибегаете к «выборке» (в Nhibernate), чтобы получить ее.

Знаете ли вы практические ситуации, когда ленивое вычисление может вас укусить…?


person Cherian    schedule 30.08.2009    source источник


Ответы (7)


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

Например, хэширование файла в Haskell. Возможно, вы имеете хорошие намерения и лениво читаете входной файл по частям, добавляя каждую часть в дайджест, но за вашей спиной Haskell на самом деле создает преобразователь для каждой части, которую вы добавляете в дайджест, оставляя весь файл в памяти. эти преобразователи до тех пор, пока результирующий дайджест не будет фактически оценен. Ой!

См. последний комментарий здесь: Отложенный ввод-вывод Haskell и закрытие файлов

person Jesse    schedule 09.06.2010

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

person vy32    schedule 30.08.2009
comment
Неправильно. Если вы должны оценить ответ, то дополнительные накладные расходы на ленивую оценку создают затраты без каких-либо преимуществ. - person vy32; 20.05.2010
comment
vy32 правильно. Например, если у вас есть список объектов, которые отображаются в списке на мобильном устройстве, представление будет создано в тот момент, когда элементы списка появятся на экране. Если некоторые значения, показанные в списке, должны быть загружены лениво, список будет заикаться и отставать, потому что новые элементы списка не могут быть заполнены достаточно быстро. - person Janusz; 09.06.2010
comment
Это не неправильно. Это просто не универсально полезно. Например, развертывание циклов — это способ повысить производительность, но это не означает, что развертывание циклов всегда приводит к повышению производительности. - person Ken; 09.06.2010
comment
@ Кен, ты прав --- я был немного резок. Комментарий Лайлы не является неправильным, но он не по теме. То есть отложенное вычисление — это способ повысить производительность, но не во всех случаях — на самом деле во многих случаях отложенное вычисление не помогает. - person vy32; 11.06.2010
comment
@Ken, развертывание циклов не является примером ленивой оценки. - person vy32; 19.10.2010
comment
@ vy32 - он не говорит, что это так. Он приводит пример того, что иногда приводит к повышению производительности. - person Rob Grant; 06.05.2014

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

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

person Zorf    schedule 19.05.2010

Один пример лени, вызывающей странные проблемы (случилось со мной сегодня, в 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 для чтения — бац!

Я знаю, что это тривиально исправить, но это трудно найти, если вы не знаете, где искать.

person jkramer    schedule 19.05.2010
comment
Эта проблема вызвана именно ленивым вводом-выводом, а не ленивым вычислением в целом. Ленивый ввод-вывод на самом деле довольно опасен и противоречит духу функционального программирования, поскольку дает побочные эффекты функциям, которые должны быть чистыми (а именно, вычисление строки приводит к чтению данных с диска — побочный эффект!), что приводит к проблемы, подобные этой, и эта тоже: stackoverflow.com/questions/2981582/ Но вы, безусловно, можете иметь ленивую оценку без ленивого ввода-вывода, на самом деле, похоже, что это текущее направление Haskell. - person Jesse; 10.06.2010

Ресурсы ленивой загрузки включают в себя переход туда и обратно между запрашивающей стороной и источником для каждой загрузки. В случае с NHibernate это означает переход от приложения к базе данных (которая часто находится на другом сервере).

С каждой поездкой часто связаны накладные расходы (конечно, для NHibernate или любого другого запроса к БД).

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

Классический пример — когда вам нужно вывести список объектов для заполнения поля со списком (часто это будут объекты конфигурации). Ленивая загрузка будет возвращаться к базе данных каждый раз, когда вы добавляете элемент списка в поле со списком. Поскольку вы помещаете весь список в поле со списком, вы понесете много дополнительных накладных расходов на ленивую выборку каждого объекта.

person Eric J.    schedule 30.08.2009

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

person David Rutten    schedule 30.08.2009

Ленивая оценка бесполезна, если вы не хотите сохранять значение, просто используйте его. Но это зависит от реализации ленивого вычислителя. Некоторые системы (например, Haskell) могут сказать, будет ли значение использоваться снова. Некоторые другие не могут и могут вызывать утечки.

person Eric Normand    schedule 24.11.2009