Hadley的新pryr软件包显示变量的地址非常适合分析。我发现无论何时将变量传递给函数,无论该函数做什么,都会创建该变量的副本。此外,如果函数体将变量传递给另一个函数,则会生成另一个副本。这是一个明显的例子
n = 100000
p = 100
bar = function(X) {
print(pryr::address(X))
}
foo = function(X) {
print(pryr::address(X))
bar(X)
}
X = matrix(rnorm(n*p), n, p)
print(pryr::address(X))
foo(X)
生成
> X = matrix(rnorm(n*p), n, p)
> print(pryr::address(X))
[1] "0x7f5f6ce0f010"
> foo(X)
[1] "0x92f6d70"
[1] "0x92f3650"
尽管功能没有做任何事情,地址每次都会改变。我对此行为感到困惑,因为我已经听说过R描述为写入时的副本 - 因此可以传递变量,但只有当函数想要写入该变量时才会生成副本。这些函数调用发生了什么?
为了获得最佳的R开发,最好不要编写多个小函数,而是将内容全部保存在一个函数中?我也在Reference Classes上找到了一些讨论,但我看到很少有R开发人员使用它。是否有另一种有效的方法来传递我遗漏的变量?
答案 0 :(得分:5)
我不完全确定,但地址可能指向指向对象的指针的内存地址。以下面的例子为例。
library(pryr)
n <- 100000
p <- 500
X <- matrix(rep(1,n*p), n, p)
l <- list()
for(i in 1:10000) l[[i]] <- X
此时,如果l
的每个元素都是X
的副本,则l
的大小将为〜3.5Tb。显然情况并非如此,因为您的计算机已开始吸烟。然而地址却不同。
sapply(l[1:10], function(x) address(x))
# [1] "0x1062c14e0" "0x1062c0f10" "0x1062bebc8" "0x10641e790" "0x10641dc28" "0x10641c640" "0x10641a800" "0x1064199c0"
# [9] "0x106417380" "0x106411d40"
答案 1 :(得分:4)
pryr::address
将未评估的符号传递给内部函数,该函数返回parent.frame()
中的地址:
pryr::address
#function (x)
#{
# address2(check_name(substitute(x)), parent.frame())
#}
#<environment: namespace:pryr>
包含上述功能可能导致返回“承诺”的地址。为了说明我们可以将pryr::address
的功能模拟为:
ff = inline::cfunction(sig = c(x = "symbol", env = "environment"), body = '
SEXP xx = findVar(x, env);
Rprintf("%s at %p\\n", type2char(TYPEOF(xx)), xx);
if(TYPEOF(xx) == PROMSXP) {
SEXP pr = eval(PRCODE(xx), PRENV(xx));
Rprintf("\tvalue: %s at %p\\n", type2char(TYPEOF(pr)), pr);
}
return(R_NilValue);
')
wrap1 = function(x) ff(substitute(x), parent.frame())
其中wrap1
相当于pryr::address
。
现在:
x = 1:5
.Internal(inspect(x))
#@256ba60 13 INTSXP g0c3 [NAM(1)] (len=5, tl=0) 1,2,3,4,5
pryr::address(x)
#[1] "0x256ba60"
wrap1(x)
#integer at 0x0256ba60
#NULL
进一步包装,我们可以看到正在构造一个“promise”对象,而不复制该值:
wrap2 = function(x) wrap1(x)
wrap2(x)
#promise at 0x0793f1d4
# value: integer at 0x0256ba60
#NULL
wrap2(x)
#promise at 0x0793edc8
# value: integer at 0x0256ba60
#NULL
# wrap 'pryr::address' like your 'bar'
( function(x) pryr::address(x) )(x)
#[1] "0x7978a64"
( function(x) pryr::address(x) )(x)
#[1] "0x79797b8"
答案 2 :(得分:3)
您可以使用profmem包(我是作者)来查看发生的内存分配。它要求您的R会话使用“profmem”功能构建:
add_filter('get_comment_author', 'my_comment_author', 10, 1);
function my_comment_author( $author = '' ) {
// Get the comment ID from WP_Query
$comment = get_comment( $comment_ID );
if (!empty($comment->comment_author) ) {
if($comment->user_id > 0){
$user=get_userdata($comment->user_id);
$author=$user->first_name.' '.substr($user->last_name,0,1).'.'; // this is the actual line you want to change
} else {
$author = __('Anonymous');
}
} else {
$author = $comment->comment_author;
}
return $author;
}
然后,你可以这样做:
data.table