gpt4 book ai didi

R:使用类属性更慢地分配给列表元素

转载 作者:行者123 更新时间:2023-12-04 11:34:36 24 4
gpt4 key购买 nike

我在 S3 和 S4 类的上下文中进行了一些分析,并观察到以下内容:

与对应的普通列表上的相同操作相比,对 S3 对象元素的简单赋值要慢 2-3 倍。

从我的角度来看,S3 类是一个带有附加属性的列表,元素只是一个数字。那么,哪些机制会消耗额外的时间呢?

value <- 1 
obj_list <- list( a = 0 )
obj_s3 <- structure( obj_list, class = "myclass" )

system.time(
replicate( 100000, obj_list$a <- value)
) # ~180 ms

system.time(
replicate( 100000, obj_s3$a <- value)
) # ~420 ms

最佳答案

一旦您将一个类添加到您的 R 变量中,您就可以使其成为受 S3 调度的对象。由于$<-行为类似于 S3 泛型,$<-将尝试根据您的对象的类进行调度。如果您查看 $<- 的 C 代码,你可以看到:

/* From src/main/subassign.c

$<-(x, elt, val)
*/
SEXP attribute_hidden do_subassign3(SEXP call, SEXP op, SEXP args, SEXP env)
{
// ... code omitted
if(DispatchOrEval(call, op, "$<-", args, env, &ans, 0, 0))
return(ans);
// ... code omitted
}
DispatchOrEval只有当参数是一个对象(即有一个类或者是一个 S4 对象)时才会启动 S3 调度。请注意,即使对于没有方法的对象,S3 调度也有开销,因为仍然必须找到默认方法。如果我们查看像 mean 这样的非原始 S3 泛型,这会更清楚一些。很明显,调度过程是:
> mean
function (x, ...)
UseMethod("mean")
<bytecode: 0x000000000fd151c0>
<environment: namespace:base>

这表明当您调用 mean 时,确实发生了以下情况。在没有方法的对象上:
mean(obj) => UseMethod() => find method => mean.default(obj)

额外的调用和查找匹配方法的过程会增加您观察到的开销。这对于像 $<- 这样的东西并不明显。或 sum因为所有这些都是通过 DispatchOrEval 中的 C 代码完成的.

为了显示:
> obj <- structure(1:10, class="wookkawooka")
> var <- 1:10
>
> library(microbenchmark)
> microbenchmark(mean(obj), mean(var), mean.default(obj))
Unit: microseconds
expr min lq mean median uq max neval
mean(obj) 12.069 13.166 16.46442 13.166 13.7145 95.813 100
mean(var) 8.046 8.777 9.51974 8.778 9.1430 31.084 100
mean.default(obj) 6.217 7.314 9.17234 7.680 8.0460 84.111 100

请注意,此处未显示差异,因为 mean.default函数本身的开销比 $<- 之类的原语要多。所以调度时间占总时间的比例较小。另外,请注意,对于非对象,调度仍然发生(与原语不同),除了可以更快地决定使用默认方法。这就是为什么 mean(var)mean.default(obj) 慢一点但比 mean(obj) 快.

这是 a blog post on S3/S4 dispatch performance 您可能会感兴趣。

关于R:使用类属性更慢地分配给列表元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29122623/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com