将对象传递给函数而不在复制时复制它

时间:2013-02-01 13:43:37

标签: r memory-management

我的问题

如果将对象x传递给修改它的函数f,R将在x的环境中创建f的修改后的本地副本,而不是更改原始对象(由于复制更改原则)。但是,我有一种情况x非常大,一旦传递到f就不需要,所以我想避免一次x f的原始副本存储} 叫做。有没有一种聪明的方法来实现这一目标?

f是一个未知的函数,由一个可能不是很聪明的用户提供。

我目前的解决方案

我到目前为止所做的最好的事情是将x包裹在一个函数forget中,该函数对名为x的{​​{1}}进行新的本地引用,删除原始引用。工作区,然后传递新的引用。问题在于我不确定它是否达到了我想要的效果,它只适用于y,这在我目前的案例中是一个交易破坏者。

globalenv()

以下是调用上述函数的示例。

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
}

底线

我正在做我希望自己做的事情吗?有更好的方法吗?

2 个答案:

答案 0 :(得分: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)原型对象也使用环境:

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

ADDED:原型解决方案

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

答案 1 :(得分:1)

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

我承认我很少使用'ff'包,而当我这样做时,我通常根本没有任何问题。但是,我并没有检查具体的内存使用情况,我的目标通常只是对数据进行大量计算。它有效,我不会问问题。