【发布时间】:2014-04-06 18:08:39
【问题描述】:
[编辑:自 R 3.1.0 以来,提示此解决方法的问题已得到修复。]
我被要求在其他地方发布这个作为自我回答的问题。
当 R 函数通过省略号参数接受任意数量的参数时,访问它们的常用方法是使用 list(...):
f <- function(...) {
dots <- list(...)
# Let's print them out.
for (i in seq_along(dots)) {
cat(i, ": name=", names(dots)[i], "\n", sep="")
print(dots[[i]])
}
}
> f(10, a=20)
1: name=
[1] 10
2: name=a
[1] 20
但是,R(从 v3.0.2 开始)深度复制所有 list 元素:
> x <- 10
> .Internal(inspect(x))
@10d85ca68 14 REALSXP g0c1 [MARK,NAM(2),TR] (len=1, tl=0) 10
> x2 <- x
> .Internal(inspect(x2)) # Not copied.
@10d85ca68 14 REALSXP g0c1 [MARK,NAM(2),TR] (len=1, tl=0) 10
> y <- list(x)
> .Internal(inspect(y[[1]])) # x was copied to a different address:
@10dd45e88 14 REALSXP g0c1 [MARK,NAM(1),TR] (len=1, tl=0) 10
> z <- list(y)
> .Internal(inspect(z)) # y was deep-copied:
@10d889ed8 19 VECSXP g0c1 [MARK,NAM(1)] (len=1, tl=0)
@10d889f38 19 VECSXP g0c1 [MARK,TR] (len=1, tl=0)
@10d889f68 14 REALSXP g0c1 [MARK] (len=1, tl=0) 10
如果您启用了内存分析,您也可以使用 tracemem 验证这一点。
所以你一直在list 中存储大对象?已复制。将它们传递给内部调用list(...) 的任何函数?已复制:
> g <- function(...) for (x in list(...)) .Internal(inspect(x))
> g(z) # Copied.
@10dd45e58 19 VECSXP g0c1 [] (len=1, tl=0)
@10dd35fa8 19 VECSXP g0c1 [] (len=1, tl=0)
@10dd36068 19 VECSXP g0c1 [] (len=1, tl=0)
@10dd36158 14 REALSXP g0c1 [] (len=1, tl=0) 10
> g(z) # ...copied again.
@10dd32268 19 VECSXP g0c1 [] (len=1, tl=0)
@10d854c68 19 VECSXP g0c1 [] (len=1, tl=0)
@10d8548d8 19 VECSXP g0c1 [] (len=1, tl=0)
@10d8548a8 14 REALSXP g0c1 [] (len=1, tl=0) 10
还不害怕?在 R 库源代码中尝试 grep -l "list(\.\.\.)" *.R。我最喜欢的是mapply/Map,我经常调用 GB 的数据,想知道为什么内存会用完。至少lapply 没问题。
那么,我怎样才能编写带有... 参数的可变参数函数并避免复制它们?
【问题讨论】:
-
我在处理列表时注意到了元素的复制,但没有意识到这是一个新的“功能”。
-
我不认为它是新的。我记下了这个版本,以防将来发生变化。
-
确实在 3.1.0 中已修复
标签: r memory arguments ellipsis copying