In R, I am looping over a vector of objects and apply the same commands at each iteration. How to (i) stop an iteration that takes too long, (ii) print a error/warning message and (iii) go ahead with the next iteration?
For instance, let's say that I have a vector containing 3 time periods and I make R sleeps for these periods, applying a time limit of 5 seconds. If a for loop iteration takes more than 5 seconds (second one of the vector here), it should stop at (around) 5 seconds and keeps going.
My problem with the below codes is that, if an iteration takes too long, R does not stop, but only prints the error message once the iteration is finished and not straight at the time limit.
vec <- c(2, 12, 3)
# using base R 'setTimeLimit' function
for(i in 1:length(vec)){
cat(". Sleeping", vec[i], "seconds\n")
tryCatch(
{
system.time(
local(
{
setTimeLimit(elapsed = 5, transient = TRUE)
Sys.sleep(vec[i])
}
)
)
},
error=function(e){cat(conditionMessage(e), "\n")}
)
}
# using R.utils 'withTimeout' function
library(R.utils)
for(i in 1:length(vec)){
cat(". Sleeping", vec[i], "seconds\n")
# first 'tryCatch' if error NOT caused by a timeout
tryCatch(
# second 'tryCatch' if error caused by a timeout
tryCatch(
withTimeout(
Sys.sleep(vec[i]),
timeout=5,
onTimeout="error"
),
TimeoutException = function(ex) cat("Timeout. Skipping.\n")
),
error=function(e){cat(conditionMessage(e), "\n")}
)
}
EDIT
As mentionned in the comments, this solution does not work neither with my example.
for(i in 1:length(vec)){
+ tryCatch(
+ expr = {
+ withTimeout({Sys.sleep(vec[i]); cat(". Sleeping ", vec[i], " seconds\n")},
+ timeout = 5)
+ },
+ TimeoutException = function(ex) cat("Timeout. Skipping.\n")
+ )
+ }
It outputs:
. Sleeping 2 seconds
Timeout. Skipping. # this message shows up after 12 seconds anyway (I am trying to stop it after timeout = 5s here)
. Sleeping 3 seconds
EDIT 2
My example involving the Sys.sleep
function does not work with withTimeout
.
From R.Utils
manual:
(*) Note that on Unix and macOS, Sys.sleep(time) will signal a timeout error only after time seconds passed, regardless of timeout limit (< time).
Taking another example, the SO post mentioned in the comments below actually works.
library(R.utils)
vec <- c(1e+02, 1e+06, 1e+04)
# the second element of the vector takes some time to run
foo <- function(i){
for(j in 1:i){
invisible(capture.output(print(j)))
}
}
# checking that the second element will take a long time (15 seconds)
system.time(foo(vec[1]))
# user system elapsed
# 0.002 0.001 0.001
system.time(foo(vec[2]))
# user system elapsed
# 11.557 3.157 15.543
system.time(foo(vec[3]))
# user system elapsed
# 0.109 0.031 0.148
for(k in vec){
tryCatch(
{
system.time(withTimeout(
{cat("... Processing ", k, " times...\n\n"); invisible(capture.output(foo(k)))},
timeout = 5
))
},
TimeoutException = function(ex) cat("Timeout. Skipping.\n\n")
)
}
#... Processing 100 times...
#
#... Processing 1e+06 times...
#
#Timing stopped at: 4.993 0.029 5.022 # it stops at timeout = 5s
#Timeout. Skipping.
#
#... Processing 10000 times...