【发布时间】:2015-01-04 01:04:58
【问题描述】:
在函数式语言中使用大型数据结构时如何减少垃圾收集时间?
(我使用的是 Racket,但这个问题适用于任何带有垃圾收集器的面向功能的语言。)
函数式编程的核心习惯是设计函数来处理数据的副本,并将处理后的数据作为结果返回,而不是从远处改变数据结构。您不必担心额外的复制,因为垃圾收集器会过来并恢复不再使用的内存。
就目前而言,这很棒。但是当我开始编写处理更大数据结构的程序时,我发现更多的总运行时间被垃圾收集占用(如 25-35% 而不是我发现的小型结构的典型 10-15% )。
这并不奇怪,因为每次函数调用都会复制更多数据,因此需要收集更多垃圾。
但这也使提高速度变得更加困难,因为垃圾收集器占用了更多的运行时间,而这基本上超出了您的控制范围。
显而易见的解决方案是完全避免复制数据。但这会让你回到从远处变异数据,这与函数式习语相矛盾。 (虽然我知道这可以在一定程度上在 Racket 中通过使用装箱值,甚至使用参数来完成。)
除此之外,我想到了三个选择:
- 设计您的数据结构,使它们对信息进行更紧凑的编码。
- 与其将整个数据结构传递给函数,不如提取您需要处理的数据子集(当然,这假设分离和重新加入数据子集的成本节省了足够的垃圾收集时间,这是值得的)。
- 在可能的情况下,将多个函数(通常会将大型数据结构从一个传递到下一个,每次都复制)组合成一个尾递归函数(不会)。
这些是有效的方法吗?还有其他我忽略的吗?
【问题讨论】:
-
也许使用Transducers 可能会有所帮助?
标签: garbage-collection scheme lisp racket