Learn R Programming

AnalysisPageServer (version 1.6.2)

eval.within.time: eval.within.time

Description

Evaluate an R expression in a fork within a given time frame

Usage

eval.within.time(expr, secs, dsecs = c(0.001, 0.1), time = as.difftime(secs, units = "secs"), verbose = FALSE, write.obj = saveRDS, read.obj = readRDS, make.con = tempfile, cleanup.con = function(con) if (file.exists(con)) unlink(con), touch.con = function(con) writeLines(character(), con), con.touched = file.exists, make.signal.con = make.con, cleanup.signal.con = cleanup.con)

Arguments

expr
Expression to evaluate
secs
Seconds to timeout. Example: 10. Ignored if time is provied.
dsecs
Seconds for parent process to sleep between checking the child process. It will be recycled to length 2. The first interval will be the first element, then each time it will wait twice as long until the interval is at least as long as the second element, then it will wait the second elemtn. This keep the ratio of time required to run and time actually taken to run close to 1 without having excessive checking for longer processes. Default: c(0.001, 0.1) (seconds).
time
difftime object giving the timeout interval. Default: as.difftime(secs, units = "secs"), which simply means to build a difftime object from the secs argument. If this argument is provided then secs is ignored.
verbose
Boolean, default FALSE. If TRUE then emit messages with process IDs, etc.
write.obj
Function to serialize and write the resulting R object to the connection. First argument is the object and second is the connection. Default: saveRDS.
read.obj
Function to read and deserialize the resulting R object from the connection. Argument is the connection. Default: readRDS.
make.con
A function to make the connection for communication between child and parent. The function will be called once with no arguments. The child will then write to it with saveRDS and the parent will read from it with readRDS. Default: tempfile.
cleanup.con
A function to clean up a conncetion. Default: function(con) if(file.exists(con)) unlink(con).
touch.con
A function to "touch" a connection. Default: function(con) writeLines(character(), con). This is used to signal through the signal file.
con.touched
A predicate to check if the connection has been touched. Default: file.exists.
make.signal.con
Same as make.con, but for the signal file. Default: make.con.
cleanup.signal.con
Like cleanup.con, but for the signal file. Default: cleanup.con.

Value

The result of evaluating expr

Details

The expression is evaluated in a child process while the parent process waits up to the given time interval. If the child process finishes quickly enough it will signal to the parent process to wake up and return a particular value. If the time interval elapses before the child process finishes then the parent wakes up anyway and kills the child, then throws an error. (You may want to wrap this function in a tryCatch block to handle the error gracefully.)

The implementation uses the fork package, which is loaded---an error is thrown if unavailable. In fact, the parent sleeps for short intervals (controlled by dsecs param), each time waking up to check if either the time has elapsed or the child has finished, then acting accordingly.

The way the child signals to the parent is via the filesystem. There are two such files: the result file and the signal file. The child writes the result of the calculation to disk as a serialized R object. Usually you should try to keep this small. Then the child touches a second file, called the "signal" file, which signals that it is finished. Both of these are temporary files. While in loop, the parent checks for existence of the signal file. After exiting the loop, the parent reads the result file. An attempt is made to delete both files before returning or throwing an error.

The child process evalutes your expression within a try block. If this evaluation results in an error, then the captured error object is passed to the parent, which then throws it again.

It is possible that the child would *start* writing the result but not finish before the time elapses. That would be considered a timeout. The thing which the parent checks is if the signal file exists.

Don't be intimidated by the large number of arguments. Typically usage involves only the first two.