如何在R中停止一个耗时太长的函数并给它一个替代方案?

gen*_*ser 18 error-handling time r

我正试图以"正确的方式"做事.有时"正确的方式"需要太长时间,具体取决于输入.我真的不知道这将是什么时候.当"正确的方式"花费太长时间时,我想要采取"黑客的方式".如何让R监视特定任务的持续时间,如果阈值已经过去,还要给它做其他事情?我想这将是try家庭的一部分,但我不太确定该怎么称呼它或谷歌.

下面的虚拟例子.如果slow.func花费的时间太长,我想interuptor停下来然后打个电话fast.func.

slow.func <- function(x){
    Sys.sleep(x)    
    print('good morning')
}

fast.func <- function(x){
    Sys.sleep(x/10) 
    print('hit snooze')
}

interuptor = function(FUN,args, time.limit, ALTFUN){
#   START MONITORING TIME HERE
    do.call(FUN,args)
#   IF FUN TAKES TOO LONG, STOP IT, CALL A
    do.call(ALTFUN,args)
}

interuptor(slow.func, list(x = 2), time.limit = 1, fast.func)
Run Code Online (Sandbox Code Playgroud)

小智 11

R包R.utils的功能evalWithTimeout几乎与您所描述的完全相同.如果您不想安装软件包,则evalWithTimeout依赖于用户友好的R基本功能setTimeLimit

您的代码看起来像这样:

library(R.utils)

slow.func <- function(x){
  Sys.sleep(10)    
  return(x^2)
}

fast.func <- function(x){
  Sys.sleep(2) 
return(x*x)
}
interruptor = function(FUN,args, time.limit, ALTFUN){
  results <- NULL
  results <- evalWithTimeout({FUN(args)},timeout=time.limit,onTimeout="warning")
  if(results==NULL){
    results <- ALTFUN(args)
  }
  return(results)
}   
interruptor(slow.func,args=2,time.limit=3,fast.func)
Run Code Online (Sandbox Code Playgroud)


and*_*ega 5

对于任何想要不依赖于R.utils包的更轻量级解决方案的人,我最终使用了基于withTimeout()代码的最小解决方案。

foo <- function() {

  time_limit <- 10

  setTimeLimit(cpu = time_limit, elapsed = time_limit, transient = TRUE)
  on.exit({
    setTimeLimit(cpu = Inf, elapsed = Inf, transient = FALSE)
  })

  tryCatch({
    # do some stuff
  }, error = function(e) {
    if (grepl("reached elapsed time limit|reached CPU time limit", e$message)) {
      # we reached timeout, apply some alternative method or do something else
    } else {
      # error not related to timeout
      stop(e)
    }
  })

}
Run Code Online (Sandbox Code Playgroud)