在lapply
函数或循环中进行垃圾收集的最快方法是什么?对我来说,显而易见的事情让事情变得非常缓慢。我做错了吗?有更快的方法吗?
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!!
在我的实际用例中,函数有点复杂,并且在每个实例之后没有gc
就失败了。我可以切换到具有更多RAM的机器,虽然它不太方便,所以我很好奇是否有更快的gc
方法可用。
更新按照Martin Morgan的建议,重新排列事物会使速度接近lapply
而没有gc
(现在在不同的机器上工作,这就是为什么时间与上述不同):
x <- 1:10000
system.time(x1 <- lapply(1:length(x), function(xi) sum(x[1:xi])))
user system elapsed
3.47 0.00 3.56
# define a function to make a sequence of a function followed by gc
sum_gc <- function(x) sum(x); invisible(gc(v=FALSE))
system.time(x3 <- lapply(1:length(x), function(xi) sum_gc(x[1:xi])))
user system elapsed
3.52 0.02 3.56
答案 0 :(得分:3)
不是答案,但比评论更长。本,这个
fun0 = function(x) sum(x, gc())
定义了一个函数,用于计算“x和gc()返回的值之和”。此
fun1 = function(x) sum(x); gc()
定义一个返回x之和的函数。 gc()
在定义函数后运行,但不是函数定义的一部分。
fun2 = function(x) {
result = sum(x)
gc()
result
}
定义一个函数,该函数计算x的总和并将其保存到函数内部存在的变量result
。然后它评估函数gc()
。然后它返回result
中包含的值,即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
在第一次评估gc()
之后,在fun2
中调用fun2
并没有真正完成任何事情。没有已分配但不再与符号关联的内存,因此不会收集垃圾。这是我们分配一些内存,使用它,删除对它的引用,然后运行垃圾收集以释放内存的情况。
fun3 = function(x) {
m = rnorm(length(x))
result = sum(m * x)
rm(m)
gc()
result
}
但是明显的垃圾收集并没有在这里做任何事情 - 当R需要的内存超过可用内存时,垃圾收集器会自动运行。如果多次调用fun3
,则每个调用内部将使用一个不再被符号引用的内存,因此将在垃圾收集器自动运行时收集。通过直接调用gc()
,您断言您的天真垃圾收集策略(一直这样做)比R更好(当需要更多内存时执行)。
哪一个可以做(写一个更好的垃圾收集器)。
但事实并非如此。
我提到过,当遇到性能或内存问题时,往往会付出代价来回顾并查看您的算法和实现。我知道这是一个“玩具”的例子,但无论如何我们都要看。你计算的是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
但是R有一个函数cumsum
,可以在内存和速度方面更有效地完成这项任务。
> 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