[回复后的问题]
感谢您的回复。在我的问题中我不清楚,为此我道歉。
我会尝试提供更多有关我们情况的细节。我们有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
答案 0 :(得分:2)
对'data.table'包的最近更改是专门为了避免在修改值时进行复制。因此,如果您的应用程序可以处理其他操作的data.tables,那么这可能是一个解决方案。 (它会很快。)
答案 1 :(得分:1)
嗯,如果你能解释为什么第一个解决方案不行,那就太好了......看起来更整洁,跑得更快。
尝试回答问题:
像foo[bar][baz] <- 42
这样的“嵌套替换”操作非常复杂,并且针对某些情况进行了优化以避免复制。但很可能您的特定用例未经过优化。这将导致大量复制和性能损失。
测试该理论的一种方法是在测试之前调用gcinfo(TRUE)
。然后你会看到第一个解决方案触发2个垃圾收集,第二个解决方案触发160个左右!
这是您的第二个解决方案的变体,它将环境转换为列表,执行其操作并将转换回环境。它与您的第一个解决方案一样快。
代码:
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))