R 加快Lappy中的垃圾收集

R 加快Lappy中的垃圾收集,r,garbage-collection,lapply,R,Garbage Collection,Lapply,在lappy函数或循环中进行垃圾收集的最快方法是什么?对我来说显而易见的事情会大大减慢速度。我做错了吗?有没有更快的办法 x <- 1:10000 system.time(xx <- lapply(1:length(x), function(xi) sum(x[1:xi]))) user system elapsed 0.02 0.00 0.02 system.time(xx <- lapply(1:length(x), function(xi) su

lappy
函数或循环中进行垃圾收集的最快方法是什么?对我来说显而易见的事情会大大减慢速度。我做错了吗?有没有更快的办法

x <- 1:10000
system.time(xx <- lapply(1:length(x), function(xi) sum(x[1:xi])))
 user  system elapsed 
   0.02    0.00    0.02 
system.time(xx <- lapply(1:length(x), function(xi) sum(x[1:xi], invisible(gc(v=FALSE)))))
   user  system elapsed 
  22.49    0.00   22.57 # a thousand times increase in time taken!!

不是一个真正的答案,但比一个评论要长。本,这个

fun0 = function(x) sum(x, gc())
定义一个函数,用于计算“x和gc()返回的值”之和。这个

定义一个函数,该函数返回x的和
gc()
在定义函数后运行,但不是函数定义的一部分

fun2 = function(x) {
    result = sum(x)
    gc()
    result
}
定义一个函数,该函数计算x的和,并将其保存到函数中存在的变量
result
。然后计算函数
gc()
。然后返回
结果中包含的值,即x的和。除了时间,还值得比较结果

test_case = 1:5
identical(sum(test_case), fun0(test_case))  # FALSE
identical(sum(test_case), fun1(test_case))  # TRUE, but no garbage collection
identical(sum(test_case), fun2(test_case))  # TRUE
在第一次计算
fun2
之后,在
fun2
中调用
gc()。没有已分配但不再与符号关联的内存,因此没有要收集的垃圾。在这种情况下,我们分配一些内存,使用它,删除对它的引用,然后运行垃圾收集来释放内存

fun3 = function(x) {
   m = rnorm(length(x))
   result = sum(m * x)
   rm(m)
   gc()
   result
}
但是显式垃圾回收在这里没有任何用处——当R需要的内存超过可用内存时,垃圾回收器会自动运行。如果已多次调用
fun3
,则每次调用中都会使用不再由符号引用的内存,因此当垃圾收集器自动运行时会收集这些内存。通过直接调用
gc()

哪一个可以做到(编写更好的垃圾收集器)

但事实并非如此

我提到,当遇到性能或内存问题时,退一步看看您的算法和实现通常是有好处的。我知道这是一个“玩具”的例子,但让我们看看。你要计算的是x元素的累积和。我会把你的实现写成

fun4 = function(i, x) sum(x[seq_len(i)])
sapply(seq_along(test_case), fun4, test_case)
哪个给

> x0 <- sapply(seq_along(test_case), fun4, test_case)
> x0
[1]  1  3  6 10 15

您真的需要在每次迭代时调用
gc
?每100步或类似的步骤调用一次就足够了。也许你也可以优化你的功能,以减少内存需求?当然,如果你能获得更多的RAM,这不是一个坏主意。很少需要直接调用
gc
!在本例中,我认为它对内存使用没有任何作用。语法很奇怪——您将调用gc的结果作为sum参数提供!通常,解决内存和性能问题的方法是一种更好的算法,而不是一台更大的机器。是的,谢谢,我很熟悉你所说的
gc
的自动性质以及这里的争论:谢谢你纠正我的函数并花时间解释。我的用例类似于
库(topicmodels);数据(联合出版社);lappy(seq(20,40,10),function(d)LDA(AssociatedPress[1:20,],d))
,构建具有不同主题数量的模型列表。有少量的主题是可以的,但是随着我逐渐扩大(1000个文档等),事情逐渐停止了(或者说,我在一个月的机器时间后变得不耐烦了……。@Ben调用
gc()
不会有帮助。所以更多的RAM/交换是我最好的选择吗?不,重新考虑你想做什么。在提供给Lappy的函数中做更多的工作,以将
LDA()
返回的大型对象减少到您希望在其上进行下游计算的任何对象。也许你只对对数可能性感兴趣?然后
fun=function(d)logLik(LDA(AssociatedPress[1:20,],d))
。每次迭代都会创建并返回(继续使用内存)一个只有几个字节而不是几个兆字节的对象。这有助于直到LDA(AssociatedPress[1:x,],d)的单个迭代的大小消耗比可用的更多的时间/内存。是的,LL是我这里的主要目标。那似乎是个好主意,谢谢,我试试看。
fun4 = function(i, x) sum(x[seq_len(i)])
sapply(seq_along(test_case), fun4, test_case)
> x0 <- sapply(seq_along(test_case), fun4, test_case)
> x0
[1]  1  3  6 10 15
> x1 <- cumsum(test_case)
> identical(x0, x1)
[1] TRUE
> test_case = seq_len(10000)
> system.time(x0 <- sapply(seq_along(test_case), fun4, test_case))
   user  system elapsed 
  2.508   0.000   2.517 
> system.time(x1 <- cumsum(test_case))
   user  system elapsed 
  0.004   0.000   0.002