Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过类似try()的方式超时R命令_R - Fatal编程技术网

通过类似try()的方式超时R命令

通过类似try()的方式超时R命令,r,R,我正在并行运行大量迭代。某些迭代比其他迭代要长很多(比如说100倍)。我想暂停这些操作,但我不想深入研究函数背后的C代码(称之为fun.C)来完成繁重的工作。我希望有类似于try()的东西,但带有time.out选项。然后我可以做一些类似的事情: for (i in 1:1000) { try(fun.c(args),time.out=60))->to.return[i] } 因此,如果fun.c在某一次迭代中花费的时间超过60秒,那么修改后的try()函数将终止它并返回警告或类

我正在并行运行大量迭代。某些迭代比其他迭代要长很多(比如说100倍)。我想暂停这些操作,但我不想深入研究函数背后的C代码(称之为fun.C)来完成繁重的工作。我希望有类似于try()的东西,但带有time.out选项。然后我可以做一些类似的事情:

for (i in 1:1000) {
    try(fun.c(args),time.out=60))->to.return[i]
}
因此,如果fun.c在某一次迭代中花费的时间超过60秒,那么修改后的try()函数将终止它并返回警告或类似的内容

有人有什么建议吗?提前感谢。

请参阅此帖子:

R.utils
包中的
evalWithTimeout

下面是一个例子:

require(R.utils)

## function that can take a long time
fn1 <- function(x)
{
    for (i in 1:x^x)
    {
        rep(x, 1000)
    }
    return("finished")
}

## test timeout
evalWithTimeout(fn1(3), timeout = 1, onTimeout = "error") # should be fine
evalWithTimeout(fn1(8), timeout = 1, onTimeout = "error") # should timeout
require(R.utils)
##可能需要很长时间的函数

fn1这听起来像是应该由分配任务给工作者的人来管理的东西,而不是应该包含在工作者线程中的东西。
多核
软件包支持某些功能的超时<代码>雪
没有,据我所知

编辑:如果你真的非常想在工作线程中使用这个功能,那么试试这个功能,灵感来自@jthetzel答案中的链接

try_with_time_limit <- function(expr, cpu = Inf, elapsed = Inf)
{
  y <- try({setTimeLimit(cpu, elapsed); expr}, silent = TRUE) 
  if(inherits(y, "try-error")) NULL else y 
}

try_with_time_limit(sqrt(1:10), 1)                   #value returns as normal
try_with_time_limit(for(i in 1:1e7) sqrt(1:10), 1)   #returns NULL

try\u with\u time\u limit您在评论中提到,您的问题在于C代码运行时间过长。根据我的经验,基于
setTimeLimit
/
evalWithTimeout
的纯R超时解决方案都不能停止C代码的执行,除非代码提供了中断R的机会

您在评论中还提到,您正在对SNOW进行并行化。如果要并行化的机器是支持分叉(即,非Windows)的操作系统,则可以在对SNOW群集上的节点的命令上下文中使用mcparallel(在
并行
包中,从
多核
派生);反过来也是如此,顺便说一句,您可以从
多核
分叉的上下文触发雪簇。如果您不是通过SNOW进行并行化,那么这个答案(当然)也适用,前提是需要使C代码超时的机器可以分叉

这有助于
eval\u fork
,这是一种由用户使用的解决方案。查看
eval_fork
函数主体下方,了解Windows中的一个黑客行为的概要以及该黑客行为的一个执行不力的半版本

eval_fork <- function(..., timeout=60){

  #this limit must always be higher than the timeout on the fork!
  setTimeLimit(timeout+5);      

  #dispatch based on method
  ##NOTE!!!!! Due to a bug in mcparallel, we cannot use silent=TRUE for now.
  myfork <- parallel::mcparallel({
    eval(...)
  }, silent=FALSE);

  #wait max n seconds for a result.
  myresult <- parallel::mccollect(myfork, wait=FALSE, timeout=timeout);

  #try to avoid bug/race condition where mccollect returns null without waiting full timeout.
  #see https://github.com/jeroenooms/opencpu/issues/131
  #waits for max another 2 seconds if proc looks dead 
  while(is.null(myresult) && totaltime < timeout && totaltime < 2) {
     Sys.sleep(.1)
     enddtime <- Sys.time();
     totaltime <- as.numeric(enddtime - starttime, units="secs")
     myresult <- parallel::mccollect(myfork, wait = FALSE, timeout = timeout);
  }

  #kill fork after collect has returned
  tools::pskill(myfork$pid, tools::SIGKILL);    
  tools::pskill(-1 * myfork$pid, tools::SIGKILL);  

  #clean up:
  parallel::mccollect(myfork, wait=FALSE);

  #timeout?
  if(is.null(myresult)){
    stop("R call did not return within ", timeout, " seconds. Terminating process.", call.=FALSE);      
  }

  #move this to distinguish between timeout and NULL returns
  myresult <- myresult[[1]];

  #reset timer
  setTimeLimit();     

  #forks don't throw errors themselves
  if(inherits(myresult,"try-error")){
    #stop(myresult, call.=FALSE);
    stop(attr(myresult, "condition"));
  }

  #send the buffered response
  return(myresult);  
}

我喜欢
R.utils::withTimeout()
,但我也希望尽可能避免包依赖性。这是一个基于R的解决方案。请注意.exit()上的
调用。即使表达式抛出错误,它也会确保删除时间限制

with_timeout <- function(expr, cpu, elapsed){
  expr <- substitute(expr)
  envir <- parent.frame()
  setTimeLimit(cpu = cpu, elapsed = elapsed, transient = TRUE)
  on.exit(setTimeLimit(cpu = Inf, elapsed = Inf, transient = FALSE))
  eval(expr, envir = envir)
}

具有\u超时点。我没想到要检查工人经理。不幸的是,我正在对多个节点进行并行化,所以我认为多核无法工作。我目前正在使用snow。这看起来很完美,但我最初对evalWithTimeout()的实验让我觉得它在C代码中根本不起作用。这似乎大大延长了正常迭代的运行时间。@Ben啊,那太糟糕了。我不熟悉
evalWithTimeout()
的内部工作原理。也许你可以试着向该软件包的作者Henrik Bengtsson(网站:)咨询关于加快速度的任何建议。谢谢你推荐该软件包。效果很好。然而,仅供参考,它说:
“evalWithTimeout”已经失效。使用“R.utils::withTimeout()”。
下面有一些不错的答案。另外,请看base R中的
?setTimeLimit
。此答案中的@Andrie注释示例还包括:我喜欢您的mcparallel解决方案。对setTimeLimit()的调用是否严格必要?i、 e.是否存在mccollect超时失败的特定情况@rpierceI不是该代码的原始作者,opencpu的人是()。据我所知,在实践中,它们不应该是严格必要的——所有可能被它们终止的R代码都是快速作用的和/或对外部代码的调用。我想它可能只是出于谨慎才出现的。谢谢。将从我的版本中删除它(讨厌不必要的腰带和背带),并在我遇到问题时报告!值得一提的是@FranzB指出了OpenCPU人员发布的一个bug防护,我现在已经将其纳入了我的答案中。威尔,我要说的是,我正在一些“生产”闪亮的应用程序中使用它(当然,与
tryCatch
紧密结合),很高兴能够限制一些函数调用的运行时间。谢谢你!
with_timeout <- function(expr, cpu, elapsed){
  expr <- substitute(expr)
  envir <- parent.frame()
  setTimeLimit(cpu = cpu, elapsed = elapsed, transient = TRUE)
  on.exit(setTimeLimit(cpu = Inf, elapsed = Inf, transient = FALSE))
  eval(expr, envir = envir)
}