If a multicore future terminates the underlying forked R process, then
it occupies one of the worker slots.
Example:
library(future)
plan(multicore, workers = 4)
stopifnot(nbrOfWorkers() == 4)
stopifnot(nbrOfFreeWorkers() == 4)
f <- future({ Sys.sleep(2) })
stopifnot(nbrOfWorkers() == 4)
stopifnot(nbrOfFreeWorkers() == 3)
v <- value(f)
stopifnot(nbrOfWorkers() == 4)
stopifnot(nbrOfFreeWorkers() == 4)
f <- future({ tools::pskill(Sys.getpid()) })
stopifnot(nbrOfWorkers() == 4)
stopifnot(nbrOfFreeWorkers() == 3)
res <- tryCatch({
v <- value(f)
}, error = identity)
stopifnot(inherits(res, "FutureError"))
conditionMessage(res)
## [1] "Failed to retrieve the result of MulticoreFuture (<none>)
## from the forked worker (on localhost; PID 1632517). Post-mortem
## diagnostic: No process exists with this PID, i.e. the forked
## localhost worker is no longer alive"
stopifnot(nbrOfWorkers() == 4)
stopifnot(nbrOfFreeWorkers() == 4) ## FAIL; here we're stuck as 3
Suggestion
Detect when forked process is terminated (cf. post-mortem analysis), and remove the corresponding MulticoreFuture from the internal FutureRegistry to free up the slot.
This should be safe to do for multicore futures, because they're transient R processes.
Issue
If a multicore future terminates the underlying forked R process, then it occupies one of the worker slots.
Example:
Suggestion
Detect when forked process is terminated (cf. post-mortem analysis), and remove the corresponding MulticoreFuture from the internal FutureRegistry to free up the slot.
This should be safe to do for multicore futures, because they're transient R processes.