R: Evaluate an R expression and interrupts it if it takes too...

withTimeout {R.utils} | R Documentation

## Evaluate an R expression and interrupts it if it takes too long

### Description

Evaluate an R expression and interrupts it if it takes too long.

### Usage

    withTimeout(expr, substitute=TRUE, envir=parent.frame(), timeout, cpu=timeout,
      elapsed=timeout, onTimeout=c("error", "warning", "silent"), ...)

### Arguments

`expr` | The R expression to be evaluated.
`substitute` | If `TRUE`, argument `expr` is `substitute()`:ed, otherwise not.
`envir` | The `environment` in which the expression should be evaluated.
`timeout, cpu, elapsed` | A `numeric` specifying the maximum number of seconds the expression is allowed to run before being interrupted by the timeout. The `cpu` and `elapsed` arguments can be used to specify whether time should be measured in CPU time or in wall time.
`onTimeout` | A `character` specifying what action to take if a timeout event occurs.
`...` | Not used.

### Details

This method utilizes `setTimeLimit`() by first setting the timeout limits, then evaluating the expression that may or may not timeout. The method is guaranteed to reset the timeout limits to be infinitely long upon exiting, regardless whether it returns normally or preemptively due to a timeout or an error.

### Value

Returns the results of the expression evaluated. If timed out, `NULL` is returned if `onTimeout` was `"warning"` or `"silent"`. If `"error"` a `TimeoutException` is thrown.

### Non-supported cases

In order to understand when this function works and when it does not, it is useful to know that it utilizes R's built-in time-out mechanism, which sets the limits on what is possible and not. From `setTimeLimit`(), we learn that:

"Time limits are checked whenever a user interrupt could occur. This will happen frequently in R code and during Sys.sleep(*), but only at points in compiled C and Fortran code identified by the code author."

More precisely, if a function is implemented in native code (e.g. C) and the developer of that function does not check for user interrupts, then you cannot interrupt that function neither via a user interrupt (e.g. Ctrl-C) nor via the built-in time out mechanism. To change this, you need to contact the developer of that piece of code and ask them to check for R user interrupts in their native code.

Furthermore, it is not possible to interrupt/break out of a "readline" prompt (e.g. `readline`() and `readLines`()) using timeouts; the timeout exception will not be thrown until after the user completes the prompt (i.e. after pressing ENTER).

System calls via `system`() and `system2()` cannot be timed out via the above mechanisms. However, in R (>= 3.5.0) these functions have argument `timeout` providing their own independent timeout mechanism.

Other examples of calls that do not support timeout are "atomic" calls that may take very long such as large object allocation and `rnorm(n)` where `n` is very large.

(*) Note that on Unix and macOS, `Sys.sleep(time)` will signal a timeout error only after `time` seconds passed, regardless of `timeout` limit (< `time`).

### Author(s)

Henrik Bengtsson

### References

[1] R help thread 'Time out for a R Function' on 2010-12-06. http://www.mail-archive.com/r-help@r-project.org/msg119344.html

### See Also

Internally, `eval`() is used to evaluate the expression and `setTimeLimit`() is used to control for timeout events.

### Examples

    # - - - - - - - - - - - - - - - - - - - - - - - - -
    # Function that takes "a long" time to run
    # - - - - - - - - - - - - - - - - - - - - - - - - -
    foo <- function() {
      print("Tic")
      for (kk in 1:100) {
        print(kk)
        Sys.sleep(0.1)
      }
      print("Tac")
    }

    # - - - - - - - - - - - - - - - - - - - - - - - - -
    # Evaluate code, if it takes too long, generate
    # a timeout by throwing a TimeoutException.
    # - - - - - - - - - - - - - - - - - - - - - - - - -
    res <- NULL
    tryCatch({
      res <- withTimeout({
        foo()
      }, timeout = 1.08)
    }, TimeoutException = function(ex) {
      message("Timeout. Skipping.")
    })

    # - - - - - - - - - - - - - - - - - - - - - - - - -
    # Evaluate code, if it takes too long, generate
    # a timeout returning NULL and generate a warning.
    # - - - - - - - - - - - - - - - - - - - - - - - - -
    res <- withTimeout({
      foo()
    }, timeout = 1.08, onTimeout = "warning")

    # The same using an expression object
    expr <- quote(foo())
    res <- withTimeout(expr, substitute = FALSE,
                       timeout = 1.08, onTimeout = "warning")

    # - - - - - - - - - - - - - - - - - - - - - - - - -
    # Evaluate code, if it takes too long, generate
    # a timeout, and return silently NULL.
    # - - - - - - - - - - - - - - - - - - - - - - - - -
    res <- withTimeout({
      foo()
    }, timeout = 1.08, onTimeout = "silent")

[Package R.utils version 2.7.0 Index]