Dear All, Since upgrading to 3.6.0, I've been getting a strange error messages from the child process when using mcparallel/mccollect. Before filing a report in the Bugzilla, I want to figure out whether I had been doing something wrong all this time and R 3.6.0 has exposed it, or whether something else is going on.
# Background # Ultimately, what I want to do is to be able to set a time limit for an expression to be evaluated that would be enforced even inside compiled code. (R.utils::withTimeout() uses base::setTimeLimit(), which can only enforce within R code.) # Implementation # The approach that my implementation, statnet.common::forkTimeout() (source attached for convenience), uses is to call mcparallel() to evaluate the expression in a child process, then mccollect() with wait=FALSE and a timeout to give it a chance to finish. If it runs past the timeout, the child process is killed and an onTimeout value is returned. (This only works on Unix-alikes, but it's better than nothing.) # The problem # Since 3.6.0---and I've tested fresh installs of 3.6.0 and 3.5.3 side- by-side---I've been getting strange messages. Running source("forkTimeout.R") # attached repeat print(forkTimeout({Sys.sleep(1);TRUE}, timeout=3)) results in [1] TRUE [1] TRUE Error in mcexit(0L) : ignoring SIGPIPE signal [1] TRUE [1] TRUE Error in mcexit(0L) : ignoring SIGPIPE signal [1] TRUE [1] TRUE [1] TRUE until interrupted. Running options(error=traceback) repeat print(forkTimeout({Sys.sleep(1);TRUE}, timeout=3)) results in sporadic messages of the form: Error in mcexit(0L) : ignoring SIGPIPE signal 6: selectChildren(jobs, timeout) 5: parallel::mccollect(child, wait = FALSE, timeout = timeout) at forkTimeout.R#75 4: withCallingHandlers(expr, warning = function(w) invokeRestart("muffleWarning")) 3: suppressWarnings(parallel::mccollect(child, wait = FALSE, timeout = timeout)) at forkTimeout.R#75 2: forkTimeout({ Sys.sleep(1) ... 1: print(forkTimeout({ Sys.sleep(1) ... So, these messages do not appear to prevent the child process from returning valid output, but I've never seen them before R 3.6.0, so I wonder if I am doing something wrong. Session info is also attached. Thanks in advance, Pavel -- Pavel Krivitsky Lecturer in Statistics National Institute of Applied Statistics Research Australia (NIASRA) School of Mathematics and Applied Statistics | Building 39C Room 154 University of Wollongong NSW 2522 Australia T +61 2 4221 3713 Web (NIASRA): http://niasra.uow.edu.au/index.html Web (Personal): http://www.krivitsky.net/research ORCID: 0000-0002-9101-3362 NOTICE: This email is intended for the addressee named and may contain confidential information. If you are not the intended recipient, please delete it and notify the sender. Please consider the environment before printing this email.
R version 3.6.0 (2019-04-26) Platform: x86_64-pc-linux-gnu (64-bit) Running under: Debian GNU/Linux buster/sid Matrix products: default BLAS: /usr/lib/x86_64-linux-gnu/atlas/libblas.so.3.10.3 LAPACK: /usr/lib/x86_64-linux-gnu/atlas/liblapack.so.3.10.3 locale: [1] LC_CTYPE=en_AU.UTF-8 LC_NUMERIC=C [3] LC_TIME=en_AU.utf8 LC_COLLATE=en_AU.UTF-8 [5] LC_MONETARY=en_AU.utf8 LC_MESSAGES=en_AU.UTF-8 [7] LC_PAPER=en_AU.utf8 LC_NAME=C [9] LC_ADDRESS=C LC_TELEPHONE=C [11] LC_MEASUREMENT=en_AU.utf8 LC_IDENTIFICATION=C attached base packages: [1] stats graphics grDevices utils datasets methods base loaded via a namespace (and not attached): [1] compiler_3.6.0 tools_3.6.0 parallel_3.6.0
#' Evaluate an \R expression with a hard time limit by forking a process #' #' This function uses #' #ifndef windows #' [parallel::mcparallel()], #' #endif #' #ifdef windows #' `parallel::mcparallel()`, #' #endif #' so the time limit is not #' enforced on Windows. However, unlike functions using [setTimeLimit()], the time #' limit is enforced even on native code. #' #' @param expr expression to be evaluated. #' @param timeout number of seconds to wait for the expression to #' evaluate. #' @param unsupported a character vector of length 1 specifying how to #' handle a platform that does not support #' #ifndef windows #' [parallel::mcparallel()], #' #endif #' #ifdef windows #' `parallel::mcparallel()`, #' #endif #' \describe{ #' #' \item{`"warning"` or `"message"`}{Issue a warning or a message, #' respectively, then evaluate the expression without the time limit #' enforced.} #' #' \item{`"error"`}{Stop with an error.} #' #' \item{`"silent"`}{Evaluate the expression without the time limit #' enforced, without any notice.} #' #' } Partial matching is used. #' @param onTimeout Value to be returned on time-out. #' #' @return Result of evaluating `expr` if completed, `onTimeout` #' otherwise. #' #' @note `onTimeout` can itself be an expression, so it is, for #' example, possible to stop with an error by passing #' `onTimeout=stop()`. #' #' @note Note that this function is not completely transparent: #' side-effects may behave in unexpected ways. In particular, RNG #' state will not be updated. #' #' @examples #' #' forkTimeout({Sys.sleep(1); TRUE}, 2) # TRUE #' forkTimeout({Sys.sleep(1); TRUE}, 0.5) # NULL (except on Windows) #' @export forkTimeout <- function(expr, timeout, unsupported = c("warning","error","message","silent"), onTimeout = NULL){ loadNamespace("parallel") loadNamespace("tools") env <- parent.frame() if(!exists("mcparallel", where=asNamespace("parallel"), mode="function")){ # fork() is not available on the system. unsupported <- match.arg(unsupported) warnmsg <- "Your platform (probably Windows) does not have fork() capabilities. Time limit will not be enforced." errmsg <- "Your platform (probably Windows) does not have fork() capabilities." switch(unsupported, message = message(warnmsg), warning = warning(warnmsg), error = stop(errmsg)) out <- eval(expr, env) }else{ # fork() is available on the system. ## TODO: The suppressWarnings() are working around a bug in ## current parallel package. They should not be necessary after ## the next R release. child <- parallel::mcparallel(eval(expr, env), mc.interactive=NA) out <- suppressWarnings(parallel::mccollect(child, wait=FALSE, timeout=timeout)) if(is.null(out)){ # Timed out with no result: kill. tools::pskill(child$pid) out <- onTimeout }else{ out <- out[[1L]] } suppressWarnings(parallel::mccollect(child)) # Clean up. } out }
______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel