Reputation: 4201
I have a piece of code whose execution time varies. Some time it takes 5 seconds, other times it could take much longer. I want to put a time limit such that if execution time hangs for more than 5 seconds, then interrupt and re-run the code (and hopefully it would run more quickly (i.e., <= 5 seconds).
I found that R.utils::withTimeout()
is good for this task. However, I'm not sure how to create the rerunning loop. Consider the following piece of code for example. square_slowly()
is a function that squares a number, with varying execution times. It could take any time between 1 to 10 seconds to run.
square_slowly <- function(x) {
idle_time <- sample(1:10, 1)
Sys.sleep(idle_time)
message(paste0("it took ", idle_time, " seconds"))
return(x * x)
}
set.seed(100)
square_slowly(3)
#> it took 10 seconds
#> [1] 9
So I want to monitor square_slowly()
: if it takes more than 5 seconds, then rerun. Repeat re-running until it runs in 5 seconds or faster.
I assume I need a repeat()
loop, but not sure how to do it.
EDIT
Ideally, I would like to add a message in case such a re-run happens. That is, for every re-run, print a message such as more than 5 seconds have elapsed; re-running.
Upvotes: 2
Views: 433
Reputation: 41230
One possible implementation:
run <- function(x,timeout) {
res <- tryCatch(R.utils::withTimeout(square_slowly(x),timeout=timeout),error=function(cond) NULL)
if (is.null(res)) res <- Recall(x,timeout)
return(res)
}
run(3,timeout = 5)
it took 4 seconds
[1] 9
Or in functional form:
run <- function(.f,...,timeout,trial=1) {
cat('run',trial,'\n')
res <- tryCatch(R.utils::withTimeout(do.call(.f,list(...)),timeout=timeout),error=function(cond) NULL)
if (is.null(res)) res <- Recall(.f=.f,unlist(list(...)),timeout=timeout,trial = trial + 1)
return(res)
}
run(square_slowly,3,timeout = 5)
run 1
run 2
run 3
run 4
run 5
run 6
it took 4 seconds
[1] 9
Upvotes: 4