【问题标题】:Writing to large matrices within a function - fast vs slow在函数中写入大型矩阵 - 快与慢
【发布时间】:2011-11-17 15:02:04
【问题描述】:

[问题在回复后修改]

感谢您的回复。我的问题不清楚,对此我深表歉意。

我会尽量详细说明我们的情况。我们有c。我们在环境中保存的 100 个矩阵。每个都很大。如果可能的话,我们希望在执行更新时避免对这些矩阵进行任何复制。我们经常遇到 2GB 内存限制,所以这对我们来说非常重要。

所以我们的两个要求是 1) 避免复制和 2) 通过名称间接寻址矩阵。速度虽然很重要,但也是一个附带问题,可以通过避免复制来解决。

在我看来,Tommy 的解决方案涉及创建一个副本(尽管它确实完全回答了我的原始问题,所以我是错误的人)。

下面的代码对我们来说是最明显的,但它显然创建了一个副本(如 memory.size 增加所示)

myenv <- new.env()
myenv$testmat1 <- matrix(1.0, nrow=6000, ncol=200)

testfnDirect <- function(paramEnv) {
    print(memory.size())

    for (i in 1:300) {
        temp <- paramEnv$testmat1[10,] 
        paramEnv$testmat1[10,] <- temp * 0
    }   
    print(memory.size())
}
system.time(testfnDirect(myenv))

使用with关键字似乎可以避免这种情况,如下图:

myenv <- new.env()
myenv$testmat1 <- matrix(1.0, nrow=6000, ncol=200)

testfnDirect <- function(paramEnv) {
    print(gc())
    varname <- "testmat1" # unused, but see text
    with (paramEnv, {
        for (i in 1:300) {
            temp <- testmat1[10,] 
            testmat1[10,] <- temp * 0
        }
    })
    print(gc())
}
system.time(testfnDirect(myenv))

但是,该代码通过直接按名称寻址 testmat1 来工作。我们的问题是我们需要间接解决它(我们事先不知道我们将更新哪些矩阵)。

有没有办法修改 testfnDirect 以便我们使用变量 varname 而不是硬编码 testmat

【问题讨论】:

  • FWIW:这个例子可能没问题,但一般来说最好避免产生缓存或记忆化可能会产生明显加速的例子。在这种情况下,很难区分我们控制范围内的优化和解释器或硬件完成的事情。

标签: r matrix


【解决方案1】:

最近对“data.table”包的更改是为了避免在修改值时复制。因此,如果您的应用程序可以处理其他操作的 data.tables,那可能是一个解决方案。 (而且会很快。)

【讨论】:

    【解决方案2】:

    好吧,如果你能解释一下为什么第一个解决方案不好……它看起来更整洁而且运行得更快。

    尝试回答问题:

    1. foo[bar][baz] &lt;- 42 这样的“嵌套替换”操作非常复杂,并且针对某些情况进行了优化以避免复制。但是很可能您的特定用例没有得到优化。这会导致大量副本,并降低性能。

      测试该理论的一种方法是在测试前致电gcinfo(TRUE)。然后您会看到第一个解决方案触发了 2 次垃圾收集,而第二个解决方案触发了 160 次左右!

    2. 这是您的第二个解决方案的变体,它将环境转换为列表,执行它的操作,然后转换回环境。它与您的第一个解决方案一样快。

    代码:

    testfnList <- function() {
        mylist <- as.list(myenv, all.names=TRUE)
    
        thisvar <- "testmat2"
        for (i in 1:300) {
            temp <- mylist[[thisvar]][10,]
            mylist[[thisvar]][10,] <- temp * 0
        }
        
        myenv <<- as.environment(mylist)
    }
    system.time(testfnList()) # 0.02 secs
    

    ...如果您将myenv 作为参数传递给函数,那当然会更整洁。 一个小的改进(如果您循环很多,而不仅仅是 300 次)将按数字而不是名称进行索引(不适用于环境,但适用于列表)。改一下thisvar:

    thisvar <- match("testmat2", names(mylist))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-20
      • 1970-01-01
      • 2015-10-11
      • 1970-01-01
      • 2017-02-15
      • 1970-01-01
      • 2014-12-03
      • 1970-01-01
      相关资源
      最近更新 更多