[英]Faster alternative to deparse()
I maintain a package that relies on repeated calls to deparse(control = c("keepNA", "keepInteger"))
.我维护一个依赖于重复调用
deparse(control = c("keepNA", "keepInteger"))
。 control
is always the same, and the expression varies. control
总是相同的,表达方式各不相同。 deparse()
seems to spend a lot of time repeatedly interpreting the same set of options with .deparseOpts()
. deparse()
似乎花了很多时间用.deparseOpts()
重复解释同一组选项。
microbenchmark::microbenchmark(
a = deparse(identity, control = c("keepNA", "keepInteger")),
b = .deparseOpts(c("keepNA", "keepInteger"))
)
# Unit: microseconds
# expr min lq mean median uq max neval
# a 7.2 7.4 8.020 7.5 7.6 55.1 100
# b 3.0 3.2 3.387 3.4 3.5 6.0 100
On some systems, redundant .deparseOpts()
calls actually take up the majority of the runtime of deparse()
( flame graph here ).在某些系统中,冗余
.deparseOpts()
调用实际占用大部分运行的deparse()
火焰图形这里)。
I would really like to just call .deparseOpts()
once and then supply the numeric code to deparse()
, but that appears impossible without calling .Internal()
or invoking the C code directly, neither of which is optimal from a package development perspective.我真的很想只调用
.deparseOpts()
一次,然后将数字代码提供给deparse()
,但如果不调用.Internal()
或直接调用 C 代码,这似乎是不可能的,从包开发的角度来看,这两者都不是最佳的.
deparse
# function (expr, width.cutoff = 60L, backtick = mode(expr) %in%
# c("call", "expression", "(", "function"),
# control = c("keepNA", "keepInteger", "niceNames",
# "showAttributes"), nlines = -1L)
# .Internal(deparse(expr, width.cutoff, backtick, .deparseOpts(control),
# nlines))
# <bytecode: 0x0000000006ac27b8>
# <environment: namespace:base>
Is there a convenient workaround?有没有方便的解决方法?
1) Define a function which generates a copy of deparse whose environment has been reset to find an altered version of .deparseOpts which has been set to be equal to the identity function. 1)定义一个函数,该函数生成 deparse 的副本,其环境已重置以找到 .deparseOpts 的更改版本,该版本已设置为等于身份函数。 In
Run
we then run that function to create a deparse2
and execute that.在
Run
我们然后运行该函数来创建一个deparse2
并执行它。 This avoids running .Internal
directly.这避免了直接运行
.Internal
。
make_deparse <- function() {
.deparseOpts <- identity
environment(deparse) <- environment()
deparse
}
Run <- function() {
deparse2 <- make_deparse()
deparse2(identity, control = 65)
}
# test
Run()
2) Another way to do this is to define a constructor function which creates an environment in which to put a modified copy of deparse
and add a trace to that copy redefining .deparseOpts
as the identity function. 2)另一种方法是定义一个构造函数,它创建一个环境,在其中放置
deparse
的修改副本并向该副本添加跟踪,将.deparseOpts
重新定义为标识函数。 Then return that environment.然后返回那个环境。 We then have some function which uses it and for this example we create a function
Run
to demonstrate it and then just execute Run
.然后我们有一些使用它的函数,对于这个例子,我们创建一个函数
Run
来演示它,然后只执行Run
。 This avoids having to use .Internal
这避免了必须使用
.Internal
make_deparse_env <- function() {
e <- environment()
deparse <- deparse
suppressMessages(
trace("deparse", quote(.deparseOpts <- identity), print = FALSE, where = e)
)
e
}
Run <- function() {
e <- make_deparse_env()
e$deparse(identity, control = 65)
}
# test
Run()
3) A third approach is to redefine deparse
by adding a new argument which sets .deparseOpts
to have a default of identity
and sets the control
to have a default of 65. 3)第三种方法是通过添加一个新参数来重新定义
deparse
,该参数将.deparseOpts
设置为具有默认identity
并将control
设置为具有默认值 65。
make_deparse65 <- function() {
deparse2 <- function (expr, width.cutoff = 60L, backtick = mode(expr) %in%
c("call", "expression", "(", "function"),
control = 65, nlines = -1L, .deparseOpts = identity) {}
body(deparse2) <- body(deparse)
deparse2
}
Run <- function() {
deparse65 <- make_deparse65()
deparse65(identity)
}
# test
Run()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.