我有一个通用函数来捕获我的包logR::tryCatch2
中包含的所有异常,定义为:
tryCatch2 <- function(expr){
V=E=W=M=I=NULL
e.handler = function(e){
E <<- e
NULL
}
w.handler = function(w){
W <<- c(W, list(w))
invokeRestart("muffleWarning")
}
m.handler = function(m){
attributes(m$call) <- NULL
M <<- c(M, list(m))
}
i.handler = function(i){
I <<- i
NULL
}
V = suppressMessages(withCallingHandlers(
tryCatch(expr, error = e.handler, interrupt = i.handler),
warning = w.handler,
message = m.handler
))
list(value=V, error=E, warning=W, message=M, interrupt=I)
}
正如您在最后一行中所看到的,它返回一个或多或少自我描述的列表
它通过简单tryCatch2
!is.null
调用后对延迟的例外做出了真实的反应:
f = function(){ warning("warn1"); warning("warn2"); stop("err") }
r = tryCatch2(f())
if(!is.null(r$error)) cat("Error detected\n")
# Error detected
if(!is.null(r$warning)) cat("Warning detected, count", length(r$warning), "\n")
# Warning detected, count 2
它按预期工作,我可以用我自己的代码做出反应。但在某些情况下,我不想停止也被捕获的中断进程。目前我似乎需要向tryCatch2
添加额外的参数,这将控制是否应该捕获中断。所以问题是关于我可以用以下方式使用的invokeInterrupt
函数:
g = function(){ Sys.sleep(60); f() }
r = tryCatch2(g())
# interrupt by pressing ctrl+c / stop while function is running!
if(!is.null(r$interrupt)) cat("HERE I would like to invoke interrupt\n")
# HERE I would like to invoke interrupt
我认为如果R能够捕获一个,它也应该能够调用一个
如何实现invokeInterrupt
功能?
答案 0 :(得分:3)
我可以提出一个部分解决方案,它依赖于tools
包。
invokeInterrupt <- function() {
require(tools)
processId <- Sys.getpid()
pskill(processId, SIGINT)
}
但是,请注意,将中断信号(SIGINT
)与pskill
一起抛出似乎不是很强大。我通过发送异常并使用您的函数捕获它来运行一些测试,如下所示:
will_interrupt <- function() {
Sys.sleep(3)
invokeInterrupt()
Sys.sleep(3)
}
r = tryCatch2(will_interrupt())
在Linux上,从R命令行执行时效果很好。在Windows上,R命令行和R Gui在执行此代码时关闭。更糟糕的是:在Linux和Windows上,这段代码立即崩溃了Rstudio ......
因此,如果要在Linux上从R命令行执行代码,则此解决方案应该没问题。否则你可能会运气不好......
答案 1 :(得分:2)
最新答案,但我发现rlang::interrupt
会抛出“用户中断”:
interrupt()允许R代码模拟通过Ctrl-C发出信号的用户中断。 当前无法创建自定义中断条件对象。
来源:?rlang::interrupt
内部调用R API函数Rf_onintr
,它是函数onintr
的别名。
interrupt
基本上是这些类的特殊条件:
interrupt
和condition
(请参阅R source code)。
如果您只想模拟一个中断来测试tryCatch
(无需中断正在运行的R语句),则可以通过signalCondition
用这些类抛出条件:
interrupt_condition <- function() {
structure(list(), class = c("interrupt", "condition"))
}
tryCatch(signalCondition(interrupt_condition()),
interrupt = function(x) print("interrupt detected"))
# [1] "interrupt detected"