5

延迟执行几乎总是一个福音。但是在某些情况下,它是一个问题,你诉诸“获取”(在 Nhibernate 中)来急切地获取它。

你知道懒惰评估会咬你的实际情况吗……?

4

7 回答 7

4

您不能使用惰性求值对恒定空间中的输入数据进行归约(例如折叠),因为每个归约步骤的延迟评估会导致线性空间复杂度。您必须改为强制评估每个缩减步骤的结果,以保持空间使用不变。

例如,在 Haskell 中对文件进行哈希处理。您可能是善意的,并且懒洋洋地逐块读取输入文件,将每个块添加到摘要中,但在您背后,Haskell 实际上是为您添加到摘要中的每个块创建一个 thunk,将整个文件留在内存中这些 thunk 直到实际评估结果摘要。哎哟!

请参阅此处的最后一条评论:Haskell 惰性 I/O 和关闭文件

于 2010-06-09T13:27:29.730 回答
3

延迟评估在性能至关重要且必须始终评估值的情况下没有用。在这些情况下,您最好只评估值并完成它,因为惰性评估的开销将被浪费。

于 2009-08-30T17:38:52.520 回答
2

懒惰导致奇怪问题的一个例子(今天发生在我身上,在 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 阅读 - 砰!

我知道修复起来很简单,但如果你不知道去哪里找,就很难找到。

于 2010-05-19T18:48:52.130 回答
2

当评估可能有副作用时,惰性评估是没有用的。这是唯一的原因,这就是为什么只有纯函数式语言才有它。如果表达式可以具有必须以特定顺序发生的副作用,那么您就不能拥有它。

除此之外,惰性评估只会获得性能,这是它的主要目标。这就是为什么一些语言禁止副作用,为了获得对这种妥协的惰性评估,另一个很好的效果是控制结构可以是常规函数。

于 2010-05-19T18:28:35.897 回答
0

当您不想存储价值时,惰性评估没有用,只需使用它即可。但这取决于惰性求值器的实现。一些系统(比如 Haskell)可以判断一个值是否会被再次使用。其他一些不能也可能导致泄漏。

于 2009-11-24T20:26:00.467 回答
0

延迟加载资源涉及每次加载的请求者和源之间的往返行程。在 NHibernate 的情况下,这意味着从应用程序到数据库(通常在不同的服务器上)。

每次旅行通常都会产生开销(NHibernate 或任何其他数据库查询肯定会产生开销)。

如果您知道您将需要全部或大部分数据,则最好一次性提取它并且只产生一次开销。

一个经典的例子是当您需要拉回对象列表以填充组合框(通常这些将是配置对象)时。每次将列表成员添加到组合框中时,延迟加载都会返回到数据库。由于您将整个列表放入组合框中,因此延迟获取每个对象会产生大量额外开销。

于 2009-08-30T17:28:54.617 回答
0

这也可能是程序的用户体验问题。当应用程序加载过程中屏幕上显示横幅时,人们会很乐意等待 5 秒,但他们讨厌在文本框中输入内容时必须等待 0.25 秒。如果急切地加载所有数据所需的时间不是那么长,您可以考虑在人们接受延迟的工作流程中的某个时间点执行此操作(例如应用程序加载、窗口弹出、按钮按下)。

于 2009-08-30T17:37:03.837 回答