gpt4 book ai didi

scala - 我应该如何避免无意中捕获函数文字中的局部作用域?

转载 作者:行者123 更新时间:2023-12-04 12:24:58 25 4
gpt4 key购买 nike

我会用 Scala 示例来问这个问题,但这很可能会影响其他允许混合命令式和函数式风格的语言。

这是一个简短的例子( 更新 ,见下文):

def method: Iterator[Int] {
// construct some large intermediate value
val huge = (1 to 1000000).toList
val small = List.fill(5)(scala.util.Random.nextInt)
// accidentally use huge in a literal
small.iterator filterNot ( huge contains _ )
}

现在 iterator.filterNot懒惰地工作,这很棒!因此,我们希望返回的迭代器不会消耗太多内存(实际上,O(1))。然而可悲的是,我们犯了一个可怕的错误:自从 filterNot是懒惰的,它保留对函数文字 huge contains _ 的引用.

因此,虽然我们认为该方法在运行时需要大量内存,并且可以在该方法终止后立即释放该内存,但实际上内存一直卡住,直到我们忘记返回的 Iterator .

(我刚刚犯了这样一个错误,花了很长时间才追查到!你可以通过堆转储来捕捉这样的事情......)

What are best practices for avoiding this problem?



似乎唯一的解决方案是仔细检查在范围结束后仍然存在并捕获中间变量的函数文字。如果您正在构建一个非严格的集合并计划返回它,这有点尴尬。谁能想到一些很好的技巧,Scala 特定的或其他的,可以避免这个问题,让我写出漂亮的代码?

更新:我之前给出的例子很愚蠢,正如下面 huynhjl 的回答所示。原来是:
def method: Iterator[Int] {
val huge = (1 to 1000000).toList // construct some large intermediate value
val n = huge.last // do some calculation based on it
(1 to n).iterator map (_ + 1) // return some small value
}

事实上,现在我对这些东西的工作原理有了更好的了解,我并不那么担心!

最佳答案

你确定你没有过度简化测试用例吗?这是我运行的内容:

object Clos {
def method: Iterator[Int] = {
val huge = (1 to 2000000).toList
val n = huge.last
(1 to n).iterator map (_ + 1)
}

def gc() { println("GC!!"); Runtime.getRuntime.gc }

def main(args:Array[String]) {
val list = List(method, method, method)
list.foreach(m => println(m.next))
gc()
list.foreach(m => println(m.next))
list.foreach(m => println(m.next))
}
}

如果我理解正确的话,因为 main即使在 gc() 之后仍在使用迭代器调用,JVM 将保留 huge对象。

这是我运行它的方式:
JAVA_OPTS="-verbose:gc" scala -cp classes Clos

这是它在最后打印的内容:
[Full GC 57077K->57077K(60916K), 0.3340941 secs]
[Full GC 60852K->60851K(65088K), 0.3653304 secs]
2
2
2
GC!!
[Full GC 62959K->247K(65088K), 0.0610994 secs]
3
3
3
4
4
4

所以它在我看来就像 huge对象被回收...

关于scala - 我应该如何避免无意中捕获函数文字中的局部作用域?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3956607/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com