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