future_promise_queue()
future_promise(
expr = NULL,
envir = parent.frame(),
substitute = TRUE,
globals = TRUE,
packages = NULL,
...,
queue = future_promise_queue()
)
An R expression. While the expr
is eventually sent to future::future()
, please use the same precautions that you would use with regular promises::promise()
expressions. future_promise()
may have to hold the expr
in a promise()
while waiting for a future worker to become available.
The environment from where global objects should be identified.
If TRUE, argument expr
is
substitute()
:ed, otherwise not.
(optional) a logical, a character vector, or a named list
to control how globals are handled.
For details, see section 'Globals used by future expressions'
in the help for future()
.
(optional) a character vector specifying packages to be attached in the R environment evaluating the future.
extra parameters provided to future::future()
A queue that is used to schedule work to be done using future::future()
. This queue defaults to future_promise_queue()
and requires that method queue$schedule_work(fn)
exist. This method should take in a function that will execute the promised future work.
Unlike future::future()
, future_promise()
returns a promise()
object that will eventually resolve the future
expr
.
When submitting future work, future (by design) will block the main R session until a worker becomes available.
This occurs when there is more submitted future work than there are available future workers.
To counter this situation, we can create a promise to execute work using future (using future_promise()
) and only begin the work if a future worker is available.
Using future_promise()
is recommended whenever a continuous runtime is used, such as with plumber or shiny.
For more details and examples, please see the vignette("future_promise", "promises")
vignette.
future_promise_queue()
: Default future_promise()
work queue to use. This function returns a WorkQueue that is cached per R session.
future_promise()
: Creates a promise()
that will execute the expr
using future::future()
.
# Relative start time
start <- Sys.time()
# Helper to force two `future` workers
with_two_workers <- function(expr) {
if (!require("future")) {
message("`future` not installed")
return()
}
old_plan <- future::plan(future::multisession(workers = 2))
on.exit({future::plan(old_plan)}, add = TRUE)
start <<- Sys.time()
force(expr)
while(!later::loop_empty()) {Sys.sleep(0.1); later::run_now()}
invisible()
}
# Print a status message. Ex: `"PID: XXX; 2.5s promise done"`
print_msg <- function(pid, msg) {
message(
"PID: ", pid, "; ",
round(difftime(Sys.time(), start, units = "secs"), digits = 1), "s " ,
msg
)
}
# `"promise done"` will appear after four workers are done and the main R session is not blocked
# The important thing to note is the first four times will be roughly the same
with_two_workers({
promise_resolve(Sys.getpid()) %...>% print_msg("promise done")
for (i in 1:6) future::future({Sys.sleep(1); Sys.getpid()}) %...>% print_msg("future done")
})
#> Loading required package: future
{
#> PID: XXX; 2.5s promise done
#> PID: YYY; 2.6s future done
#> PID: ZZZ; 2.6s future done
#> PID: YYY; 2.6s future done
#> PID: ZZZ; 2.6s future done
#> PID: YYY; 3.4s future done
#> PID: ZZZ; 3.6s future done
}
#> NULL
# `"promise done"` will almost immediately, before any workers have completed
# The first two `"future done"` comments appear earlier the example above
with_two_workers({
promise_resolve(Sys.getpid()) %...>% print_msg("promise")
for (i in 1:6) future_promise({Sys.sleep(1); Sys.getpid()}) %...>% print_msg("future done")
})
{
#> PID: XXX; 0.2s promise done
#> PID: YYY; 1.3s future done
#> PID: ZZZ; 1.4s future done
#> PID: YYY; 2.5s future done
#> PID: ZZZ; 2.6s future done
#> PID: YYY; 3.4s future done
#> PID: ZZZ; 3.6s future done
}
#> NULL