循环越来越慢的问题

8

我很难理解为什么这段代码(改编自R基准测试2.5)在迭代次数增加时会变得越来越慢(平均而言)。

require(Matrix)  
c <- 0;
for (i in 1:100) {
  a <- new("dgeMatrix", x = rnorm(3250 * 3250), Dim = as.integer(c(3250, 3250)))
  b <- as.double(1:3250)

  invisible(gc())
  timing <- system.time({
    c <- solve(crossprod(a), crossprod(a, b))
  })
  print(timing)

  rm(a, b, c)
}

这里有一个示例输出,每次运行会略有不同。
据我所知,在每次迭代之间不应该保存任何东西,但是计时器从前几个循环的 1 秒钟慢慢增加到后来的 4 秒钟以上。您有任何想法是什么原因引起的,以及如何解决?
将 for 循环替换为 apply 似乎会产生类似的结果。
我知道代码没有被优化,但是它来自广泛使用的基准测试,并且取决于导致这种行为的原因,它可能表明其结果存在严重偏差(默认情况下只迭代 3 次)。
我在 Mac OS 10.8.4 上运行 R 版本 3.0.1 (x86_64),拥有 16 GB 的 RAM(其中大部分都是空闲的)。BLAS 是 OpenBLAS。

在我的电脑上,每次迭代大约需要30秒。我进行了10次迭代,它们都大约需要30-35秒的时间。 - Roman Luštrik
R 3.0.0 Mac OS 10.8:每次运行约30秒,前15次没有减速。 - Ian Fellows
OP:你真的能在那个 3250-by-3250 的矩阵上获得 ~1 秒的速度吗?你的电脑是不是吃了兴奋剂?还是你测试的时候用的是更小的维度?另一个重要的问题是:这种恶化是暂时的(在那个 for 循环的评估内)还是永久的?为了找出答案,在 for 循环结束后手动运行几次额外的迭代,告诉我们它们是慢速(4 秒)还是快速(1 秒)。 - flodel
@GSee 慢速运行是逐步加剧的,20次迭代后为1.1秒,40次迭代后为2.4秒,以此类推。 - RenéR
这更像是一个BLAS(具体来说是OpenBLAS)的问题,而不是一个R的问题。重新打标签... - Hong Ooi
显示剩余8条评论
2个回答

1
一种解决方案是使用编译器包将代码编译成字节码。这样可以消除奇怪的时间问题,因为每次迭代都会调用相同的已编译代码。它还应该使您的代码更快。要在代码上启用编译器,请包含以下两行:
library(compiler)
enableJIT(3)

如果编译代码不能解决问题,那么可疑问题的范围将被缩小。

0
也许你可以尝试将for循环中的代码制作成一个函数。这样就没有办法让一个运行影响到另一个了。而且,它还能消除由于过度使用rm()和gc()而引起的混乱。
require(Matrix)

NewFun <- function() {
    a <- new("dgeMatrix", x = rnorm(3250 * 3250), Dim = as.integer(c(3250, 3250)))
    b <- as.double(1:3250)
    timing <- system.time({
        c <- solve(crossprod(a), crossprod(a, b))
    })
    print(timing)
}

for (i in 1:100) {
    NewFun()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接