简体   繁体   中英

How to interrupt a function within a loop after a certain time in R?

I'm running an algorithm several times through a for loop in R. My loop is very basic and looks like this.

iter <- 5 #number of iterations
result <- list()

for (i in 1:iter) {
fit <- algorithm() #this is an example function that starts the algorithm
result[[i]] <- print(fit)
}

The problem is that the running times vary greatly with each run. There are runs that take only 10 minutes, others take over an hour. However, I know that the longer running times are due to the fact that the algorithm has problems because of the initial values and that the results of these runs will be wrong anyway.

So, I am now looking for a solution that (1) interrupts the function (ie algorithm() in the example above) after eg 1000 seconds, (2) proceeds with the for loop and (3) adds an additional iteration for each interruption. So, in the end, I want results from five runs with a running time less than 1000 seconds.

Does anyone have an idea? Is this even technically possible? Thanks in advance!

I think you can use setTimeLimit for this.

Quick demo:

setTimeLimit(elapsed = 2)
Sys.sleep(999)
# Error in Sys.sleep(999) : reached elapsed time limit
setTimeLimit(elapsed = Inf)

(It's important to note that you should return the time limit setting when you no longer desire its interruption.)

My "complex algorithm" will sleep a random length. Those random lengths are

set.seed(42)
sleeps <- sample(10, size=5)
sleeps
# [1]  1  5 10  8  2

I'm going to set an arbitrary limit of 6 seconds, beyond which the sleep will be interrupted and we'll get no return value. This should interrupt the third and fourth elements.

iter <- 5
result <- list()
for (i in seq_len(iter)) {
  result[[i]] <- tryCatch({
    setTimeLimit(elapsed = 6)
    Sys.sleep(sleeps[[i]])
    setTimeLimit(elapsed = Inf)
     c(iter = i, slp = sleeps[[i]])
  }, error = function(e) NULL)
}
result
# [[1]]
# iter  slp 
#    1    1 
# [[2]]
# iter  slp 
#    2    5 
# [[3]]
# NULL
# [[4]]
# NULL
# [[5]]
# iter  slp 
#    5    2 

If you have different "sleeps" and you end up with a shorter object than you need, just append it:

result <- c(result, vector("list", 5 - length(result)))

I'll enhance this slightly, for a couple of things:

  • I prefer lapply to for loops when filling result in this way; and
  • since complex algorithms can fail for other reasons, if my sleep failed early then the time limit would not be reset, so I'll use on.exit , which ensures that a function will be called when its enclosure exits, whether due to error or not.
result <- lapply(seq_len(iter), function(i) {
  setTimeLimit(elapsed = 6)
  on.exit(setTimeLimit(elapsed = Inf), add = TRUE)
  tryCatch({
    Sys.sleep(sleeps[i])
    c(iter = i, slp = sleeps[i])
  }, error = function(e) NULL)  
})
result
# [[1]]
# iter  slp 
#    1    1 
# [[2]]
# iter  slp 
#    2    5 
# [[3]]
# NULL
# [[4]]
# NULL
# [[5]]
# iter  slp 
#    5    2 

In this case, result is length 5, since lapply will always return something for each iteration. (The use of lapply is idiomatic for R, where its efficiencies are often in apply and map -like methods, unlike other languages where real speed is realized with literal for loops.)

(BTW: instead of the on.exit logic, I could have used tryCatch(..., finally=setTimeLimit(elapsed=Inf)) as well.)

An alternative to the on.exit logic is to use setTimeLimit(.., transient=TRUE) from within the execution block to be limited. That would make this code

result <- lapply(seq_len(iter), function(i) {
  tryCatch({
    setTimeLimit(elapsed = 6, transient = TRUE)
    Sys.sleep(sleeps[i])
    c(iter = i, slp = sleeps[i])
  },
  error = function(e) NULL)
})

One benefit of this is that regardless of the success/interruption of the limited code block, once that is done then the limit is immediately lifted, so there is less risk of inadvertently leaving it in place.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM