2

我的问题

如果一个对象x被传递给一个f修改它的函数,R 将创建一个修改后的本地副本xwithinf的环境,而不是更改原始对象(由于 copy-on-change 原则)。但是,我有一种情况,x它非常大并且一旦传递给就不需要了f,所以我想避免存储x一次f调用的原始副本。有没有聪明的方法来实现这一目标?

f是一个可能不太聪明的用户提供的未知功能。

我目前的解决方案

到目前为止,我最好的方法是包装x一个函数,该函数对calledforget进行新的本地引用,删除工作区中的原始引用,然后传递新的引用。问题是我不确定它是否能完成我想要的,它只适用于,这在我目前的情况下是一个交易破坏者。xyglobalenv()

forget <- function(x){
    y <- x
    # x and y now refers to the same object, which has not yet been copied
    print(tracemem(y))
    rm(list=deparse(substitute(x)), envir=globalenv())
    # The outside reference is now removed so modifying `y`
    # should no longer result in a copy (other than the
    # intermediate copy produced in the assigment)
    y
}

f <- function(x){
    print(tracemem(x))
    x[2] <- 9000.1
    x
}

这是调用上述函数的示例。

> a <- 1:3
> tracemem(a)
[1] "<0x2ac1028>"
> b <- f(forget(a))
[1] "<0x2ac1028>"
[1] "<0x2ac1028>"
tracemem[0x2ac1028 -> 0x2ac1e78]: f 
tracemem[0x2ac1e78 -> 0x308f7a0]: f 
> tracemem(b)
[1] "<0x308f7a0>"
> b
[1]    1.0 9000.1    3.0
> a
Error: object 'a' not found

底线

我在做我希望我做的事吗?有更好的方法吗?

4

2 回答 2

5

(1) 环境您可以为此使用环境:

e <- new.env()
e$x <- 1:3
f <- function(e) with(e, x <- x + 1)
f(e)
e$x

(2) 参考类或因为参考类自动使用环境使用那些:

E <- setRefClass("E", fields = "x",
    methods = list(
        f = function() x <<- x + 1
    )
)
e <- E$new(x = 1:3)
e$f()
e$x

(3) proto 对象也使用环境:

library(proto)
p <- proto(x = 1:3, f = function(.) with(., x <- x + 1))
p$f()
p$x

添加:原型解决方案

更新:将函数名称更改f为与问题一致。

于 2013-02-01T16:01:04.587 回答
1

我认为最简单的方法是只将工作副本加载到内存中,而不是同时加载原始(全局命名空间)和工作副本(函数命名空间)。您可以通过使用“ff”包将“x”和“y”数据集定义为“ffdf”数据框来回避整个问题。据我了解,“ffdf”数据帧驻留在磁盘上,仅在需要部分数据帧时才加载到内存中,并在不再需要这些部分时清除。从理论上讲,这意味着数据将被加载到内存中以复制到函数命名空间中,然后在复制完成后清除。

我承认我很少需要使用 'ff' 包,而且当我这样做时,我通常根本没有任何问题。不过,我并没有检查特定的内存使用情况,我的目标通常只是对数据执行大型计算。它有效,我不问问题。

于 2013-02-01T15:15:20.083 回答