mirai
supplies its own as.promise()
method, allowing it to be used as a promise from the promises
package.
These are next-generation, event-driven promises, developed in collaboration with Joe Cheng.
later
loop like other promises.A ‘mirai’ may be piped directly using the promise pipe %...>%
, which implicitly calls as.promise()
on the ‘mirai’. Similarly all promise-aware functions such as promises::then()
or shiny::ExtendedTask$new()
which take a promise can also take a ‘mirai’ (using promises
>= 1.3.0).
Alternatively, a ‘mirai’ may be explicitly converted into a promise by as.promise()
, which then allows using the methods $then()
, $finally()
etc.
The following example outputs “hello” to the console after one second when the ‘mirai’ resolves.
library(mirai)
library(promises)
p <- mirai({Sys.sleep(1); "hello"}) %...>% cat()
p
#> <Promise [pending]>
It is possible to both access a ‘mirai’ value at $data
and to use a promise for enacting a side effect (assigning the value to an environment in the example below).
env <- new.env()
m <- mirai({
Sys.sleep(1)
"hello"
})
promises::then(m, function(x) env$res <- x)
m[]
#> [1] "hello"
After returning to the top level prompt:
env$res
#> [1] "hello"
A mirai_map
also has an as.promise()
method, which allows it to be used directly in a Shiny ExtendedTask.
The implementation uses promises::promise_all()
, and will resolve when the entire map operation completes or at least one mirai in the map is rejected.
The following example prints the list 1, 2, 3 to the console after the flatmap returns a vector of the same values.
library(mirai)
library(promises)
with(daemons(2), {
mp <- mirai_map(1:3, function(x) { Sys.sleep(x); x })
mp %...>% print
mp[.flat]
})
#> [1] 1 2 3
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 2
#>
#> [[3]]
#> [1] 3
The code below is taken from the challenge to launch and collect one million promises. For illustration, the example is scaled down to ten thousand.
library(mirai)
daemons(8, dispatcher = FALSE)
#> [1] 8
r <- 0
start <- Sys.time()
m <- mirai_map(1:10000, \(x) x, .promise = \(x) r <<- r + x)
Sys.time() - start
#> Time difference of 3.441591 secs
later::run_now()
r
#> [1] 50005000
daemons(0)
#> [1] 0
The one million promises challenge took 6 mins 25 secs to complete using an Intel i7 11th gen mobile processor with 16GB RAM.