async {async}R Documentation

Create an asynchronous task from sequential code.

Description

async({...}), with an expression written in its argument, allows that expression to be evaluated in an asynchronous, or non-blocking manner. async returns an object with class c("async", "promise") which implements the promise interface.

Usage

async(expr, ..., split_pipes = TRUE, trace = trace_)

await(prom)

with_prefix(prefix)

Arguments

expr

An expression, to be executed asynchronously.

...

Undocumented.

split_pipes

Rewrite chained calls that use await (see below)

trace

Enable verbose logging by passing a function to trace, like async(trace=cat, {...}). trace should take a character argument. Helper with_prefix makes a function that prints a message with the given prefix. You can also say something like trace=browser for "single stepping" through an async.

prom

A promise, or something that can be converted to such by promises::as.promise().

prefix

Character prefix to print before the trace.

Details

An example Shiny app using async/await is on Github: https://github.com/crowding/cranwhales-await

When an async object is activated, it will evaluate its expression until it reaches the keyword await. The async object will return to its caller and preserve the partial state of its evaluation. When the awaited value is resolved, evaluation continues from where the async left off.

When an async block finishes (either by reaching the end, or using return()), the promise resolves with the resulting value. If the async block stops with an error, the promise is rejected with that error.

The syntax rules for an async are analogous to those for gen(); await must appear only within the arguments of functions for which there is a pausable implementation (See ⁠[pausables()]⁠). By default split_pipes=TRUE is enabled and this will reorder some expressions to satisfy this requirement.

Async blocks and generators are conceptually related and share much of the same underlying mechanism. You can think of one as "output" and the other as "input". A generator pauses until a value is requested, runs until it has a value to output, then pauses again. An async runs until it requires an external value, pauses until it receives the value, then continues.

When split_pipes=FALSE, await() can only appear in the arguments of pausables and not ordinary R functions. This is a inconvenience as it prevents using await() in a pipeline. async by default has split_pipes=TRUE which enables some syntactic sugar: if an await() appears in the leftmost, unnamed, argument of an R function, the pipe will be "split" at that call using a temporary variable. For instance,

async(makeRequest() |> await() |> sort())

will be effectively rewritten to something like

async({.tmp <- await(makeRequest()); sort(.tmp)})

This works only so long as await appears in calls that evaluate their leftmost arguments normally. split_pipes can backfire if the outer call has other side effects; for instance suppressWarnings(await(x)) will be rewritten as {.tmp <- await(x); suppressWarnings(x)}, which would defeat the purpose.

Value

async() returns an object with class "promise" as described by the promises package (i.e. not the promises used in R's lazy evaluation.)

In the context of an async, await(x) returns the resolved value of a promise x, or stops with an error.

Examples

myAsync <- async(for (i in 1:4) {
  await(delay(5))
  cat(i, "\n")
}, trace=with_prefix("myAsync"))


[Package async version 0.2.1 Index]