Skipping slow tasks in a loop in R

492 views Asked by At

I'm trying to run a simulation in R where I make a whole bunch of phylogenetic trees. The tree simulation is a bit of a problem because its run time is highly variable, sometimes 0.005 seconds and sometimes minutes. I want to avoid the slow trees so I'm trying to use evalWithTimeout to skip them. So far I'm having problems because I can't make it kill slow tasks without also killing the loop. My problem is similar to this question but the solution to that question hasn't helped me.

library(TreeSim)
library(R.utils)
for (i in 1:100){
  tryCatch(
    expr = {
      evalWithTimeout(sim.rateshift.taxa(10,1,c(0.5,2),c(0.5,0),
                                         c(1,1),c(0,0.5),complete=F),
      timeout=0.005)
    }, 
    TimeoutException = function(ex) cat("Timeout. Skipping.\n")
  )
  print(i)
}

This is what I have so far. I would like to it continue printing "i" regardless of whether the simulation goes over the time limit, but currently it gives me "reached CPU time limit" errors and stops.

2

There are 2 answers

2
Ahmed Masud On BEST ANSWER

Using https://www.rdocumentation.org/packages/R.utils/versions/2.5.0/topics/withTimeout as a source. Here's a test unit that works as expected.

foo = function() {
    print("Tic");
    x <- ceiling(runif(1) * 100)+1;
    for (kk in 1:x) {
        print(kk);
        Sys.sleep(runif(1));
    }
    print("Tac");
}

bar = function() { 
  for (i in 1:100) { 
    tryCatch({
      res <- withTimeout({
        foo();
     }, timeout=1.08);
    }, TimeoutException=function(ex) {
        cat("Timeout. Skipping.\n");
       }); 
    print(i); 
   } 
}

So the question is, is there an error that is thrown by interrupting by sim.rateshift.taxa that is not being caught, use error as thc mentions in order to catch that but use the TimeoutException to skip over proper timeouts

There is also a problem with setting too low a time limit:

https://github.com/mhahsler/arules/issues/22

You may want to simply use setTimeLimit yourself and ensure that transient is set to TRUE that way you have finer control.

Here's an example taken from http://blog.revolutionanalytics.com/2014/10/r-in-production-controlling-runtime.html

system.time(Sys.sleep(5))

##user system elapsed 
## 0.000 0.000 5.005

system.time(local({
  setTimeLimit(elapsed = 1, transient = TRUE)
  Sys.sleep(5)
}))

## Error in Sys.sleep(5): reached elapsed time limit

## Timing stopped at: 0 0 5.006
3
thc On

Try this:

library(TreeSim)
library(R.utils)
for (i in 1:100){
  tryCatch(
    expr = {
      evalWithTimeout(sim.rateshift.taxa(10,1,c(0.5,2),c(0.5,0),
                                         c(1,1),c(0,0.5),complete=F), timeout=0.005)
    }, error = function(ex) cat("Timeout. Skipping.\n"))
  print(i)
}

As @AhmedMasud mentions in the comment, the function is throwing a different error. So using error = ... catches any other issue as well.