I recently attended Henrik Bengtsson’s excellent UseR! 2026 workshop on the {futureverse}. Here are a few examples to show what it does.

library(future)
library(future.mirai)
library(tictoc)
library(tidyverse)

I’ll use this to create a slow running process.

rnorm_mean <- function(n, mean = 0, sd = 1) {
  rnorm(n, mean, sd) |> mean()
}

First go sequential:

set.seed(42)
res_list <- list()

tic()
res_list$big1   <- rnorm_mean(2^27)
res_list$big2   <- rnorm_mean(2^27)
res_list$little <- rnorm_mean(20)
toc()
9.95 sec elapsed

Here are the means:

res_list
$big1
[1] 7.712652e-07

$big2
[1] 2.779673e-05

$little
[1] 0.005492432

Now same again concurrently. I’ve added in a “huge” variant to demo something…

plan(mirai_multisession, workers = 5)
set.seed(42)
future_list <- list()

tic()
future_list$big1   <- rnorm_mean(2^27) |> future(seed = TRUE)
future_list$big2   <- rnorm_mean(2^27) |> future(seed = TRUE)
future_list$huge   <- rnorm_mean(2^28) |> future(seed = TRUE)
future_list$little <- rnorm_mean(20)   |> future(seed = TRUE)
toc()
0.11 sec elapsed

Those have zoomed off on concurrent processes so R is still able to run further commands.

6 * 7
[1] 42

Check the value of the “little” one. This would block until it’s done but it should have been swift, despite being run last.

tic()
future_list$little |> value()
[1] -0.03712671
toc()
0.19 sec elapsed

Now take a look at the two “big” ones – this will block until they’re done:

tic()
future_list[c("big1", "big2")] |> map(value)
$big1
[1] 5.73721e-06

$big2
[1] 1.912083e-05
toc()
8.02 sec elapsed

Take a look to see whether “huge” is done yet (and check the other completed ones, for completeness).

future_list |> map(resolved)
$big1
[1] TRUE

$big2
[1] TRUE

$huge
[1] FALSE

$little
[1] TRUE

Can’t really be arsed waiting, so cancel it:

cancel(future_list$huge)

Check out its status:

future_list$huge
MiraiMultisessionFuture:
Label: <unnamed-3>
Expression:
rnorm_mean(2^28)
Globals: 1 objects totaling 2.83 KiB (function ‘rnorm_mean’ of 2.52 KiB)
Packages: 1 packages (‘stats’)
L'Ecuyer-CMRG RNG seed: c(10407, -1930318427, 797483284, 260641878, -1473084223, 1251695862, 1671345826)
Capture standard output: TRUE
Capture condition classes: ‘condition’ (excluding ‘<none>’)
Immediate condition classes: ‘immediateCondition’
Lazy evaluation: FALSE
Local evaluation: TRUE
Early signaling: FALSE
Actions: [n=3] ‘run’, ‘cancel’, ‘interrupt’
State: ‘canceled’ ("Future was canceled and interrupted")
Resolved: TRUE
Unique identifier: 3cc219d778a7ad023d990bb21d8b199e-3
Owner process: 3cc219d778a7ad023d990bb21d8b199e
Class: ‘MiraiMultisessionFuture’, ‘MiraiFuture’, ‘MultiprocessFuture’, ‘Future’
Value: <not collected>
Conditions captured: <none>

The real power of {future} is how it automagically futurizes calls like maps and bootstraps, hiding the future and value calls, but I found these examples handy to get to grips with what it’s doing.

LS0tDQp0aXRsZTogIlBsYXlpbmcgd2l0aCBmdXR1cmVzIg0KYXV0aG9yOiBBbmRpIEZ1Z2FyZA0KZGF0ZTogMTMgSnVseSAyMDI2DQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOiANCiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUNCi0tLQ0KDQoNCkkgcmVjZW50bHkgYXR0ZW5kZWQgSGVucmlrIEJlbmd0c3NvbidzIGV4Y2VsbGVudCBVc2VSISAyMDI2IHdvcmtzaG9wIG9uIHRoZSB7ZnV0dXJldmVyc2V9LiBIZXJlIGFyZSBhIGZldyBleGFtcGxlcyB0byBzaG93IHdoYXQgaXQgZG9lcy4NCg0KDQpgYGB7cn0NCmxpYnJhcnkoZnV0dXJlKQ0KbGlicmFyeShmdXR1cmUubWlyYWkpDQpsaWJyYXJ5KHRpY3RvYykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCg0KSSdsbCB1c2UgdGhpcyB0byBjcmVhdGUgYSBzbG93IHJ1bm5pbmcgcHJvY2Vzcy4NCg0KYGBge3J9DQpybm9ybV9tZWFuIDwtIGZ1bmN0aW9uKG4sIG1lYW4gPSAwLCBzZCA9IDEpIHsNCiAgcm5vcm0obiwgbWVhbiwgc2QpIHw+IG1lYW4oKQ0KfQ0KYGBgDQoNCg0KRmlyc3QgZ28gc2VxdWVudGlhbDoNCg0KYGBge3J9DQpzZXQuc2VlZCg0MikNCnJlc19saXN0IDwtIGxpc3QoKQ0KDQp0aWMoKQ0KcmVzX2xpc3QkYmlnMSAgIDwtIHJub3JtX21lYW4oMl4yNykNCnJlc19saXN0JGJpZzIgICA8LSBybm9ybV9tZWFuKDJeMjcpDQpyZXNfbGlzdCRsaXR0bGUgPC0gcm5vcm1fbWVhbigyMCkNCnRvYygpDQpgYGANCg0KSGVyZSBhcmUgdGhlIG1lYW5zOg0KDQpgYGB7cn0NCnJlc19saXN0DQpgYGANCg0KTm93IHNhbWUgYWdhaW4gY29uY3VycmVudGx5LiBJJ3ZlIGFkZGVkIGluIGEgImh1Z2UiIHZhcmlhbnQgdG8gZGVtbyBzb21ldGhpbmcuLi4NCg0KDQpgYGB7cn0NCnBsYW4obWlyYWlfbXVsdGlzZXNzaW9uLCB3b3JrZXJzID0gNSkNCnNldC5zZWVkKDQyKQ0KZnV0dXJlX2xpc3QgPC0gbGlzdCgpDQoNCnRpYygpDQpmdXR1cmVfbGlzdCRiaWcxICAgPC0gcm5vcm1fbWVhbigyXjI3KSB8PiBmdXR1cmUoc2VlZCA9IFRSVUUpDQpmdXR1cmVfbGlzdCRiaWcyICAgPC0gcm5vcm1fbWVhbigyXjI3KSB8PiBmdXR1cmUoc2VlZCA9IFRSVUUpDQpmdXR1cmVfbGlzdCRodWdlICAgPC0gcm5vcm1fbWVhbigyXjI4KSB8PiBmdXR1cmUoc2VlZCA9IFRSVUUpDQpmdXR1cmVfbGlzdCRsaXR0bGUgPC0gcm5vcm1fbWVhbigyMCkgICB8PiBmdXR1cmUoc2VlZCA9IFRSVUUpDQp0b2MoKQ0KYGBgDQoNClRob3NlIGhhdmUgem9vbWVkIG9mZiBvbiBjb25jdXJyZW50IHByb2Nlc3NlcyBzbyBSIGlzIHN0aWxsIGFibGUgdG8gcnVuIGZ1cnRoZXIgY29tbWFuZHMuDQoNCmBgYHtyfQ0KNiAqIDcNCmBgYA0KDQpDaGVjayB0aGUgdmFsdWUgb2YgdGhlICJsaXR0bGUiIG9uZS4gVGhpcyB3b3VsZCBibG9jayB1bnRpbCBpdCdzIGRvbmUgYnV0IGl0IHNob3VsZCBoYXZlIGJlZW4gc3dpZnQsIGRlc3BpdGUgYmVpbmcgcnVuIGxhc3QuDQoNCmBgYHtyfQ0KdGljKCkNCmZ1dHVyZV9saXN0JGxpdHRsZSB8PiB2YWx1ZSgpDQp0b2MoKQ0KYGBgDQoNCk5vdyB0YWtlIGEgbG9vayBhdCB0aGUgdHdvICJiaWciIG9uZXMgLS0gdGhpcyB3aWxsIGJsb2NrIHVudGlsIHRoZXkncmUgZG9uZToNCg0KYGBge3J9DQp0aWMoKQ0KZnV0dXJlX2xpc3RbYygiYmlnMSIsICJiaWcyIildIHw+IG1hcCh2YWx1ZSkNCnRvYygpDQpgYGANCg0KVGFrZSBhIGxvb2sgdG8gc2VlIHdoZXRoZXIgImh1Z2UiIGlzIGRvbmUgeWV0IChhbmQgY2hlY2sgdGhlIG90aGVyIGNvbXBsZXRlZCBvbmVzLCBmb3IgY29tcGxldGVuZXNzKS4NCg0KYGBge3J9DQpmdXR1cmVfbGlzdCB8PiBtYXAocmVzb2x2ZWQpDQpgYGANCg0KQ2FuJ3QgcmVhbGx5IGJlIGFyc2VkIHdhaXRpbmcsIHNvIGNhbmNlbCBpdDoNCg0KYGBge3J9DQpjYW5jZWwoZnV0dXJlX2xpc3QkaHVnZSkNCmBgYA0KDQpDaGVjayBvdXQgaXRzIHN0YXR1czoNCg0KYGBge3J9DQpmdXR1cmVfbGlzdCRodWdlDQpgYGANCg0KVGhlIHJlYWwgcG93ZXIgb2Yge2Z1dHVyZX0gaXMgaG93IGl0IGF1dG9tYWdpY2FsbHkgZnV0dXJpemVzIGNhbGxzIGxpa2UgbWFwcyBhbmQgYm9vdHN0cmFwcywgaGlkaW5nIHRoZSAqZnV0dXJlKiBhbmQgKnZhbHVlKiBjYWxscywgYnV0IEkgZm91bmQgdGhlc2UgZXhhbXBsZXMgaGFuZHkgdG8gZ2V0IHRvIGdyaXBzIHdpdGggd2hhdCBpdCdzIGRvaW5nLg0KDQoNCg==