通过类似try()的方式超时R命令
我正在并行运行大量迭代。某些迭代比其他迭代要长很多(比如说100倍)。我想暂停这些操作,但我不想深入研究函数背后的C代码(称之为fun.C)来完成繁重的工作。我希望有类似于try()的东西,但带有time.out选项。然后我可以做一些类似的事情:通过类似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()函数将终止它并返回警告或类
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)
}