Il framework future
Utilizzi plan(multisession) e future() per un'elaborazione parallela asincrona e portabile
Il framework future è una lezione R Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento R Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso R Academy include 4 lezioni in totale.
Che cos'è il pacchetto future?
Il pacchetto future fornisce un'API unificata di alto livello per la programmazione asincrona e parallela in R. Un future è un segnaposto per un valore che sarà disponibile in seguito, eventualmente calcolato su un altro core o su un'altra macchina.
library(future)
# A simple future: computation happens asynchronously
f <- future({
Sys.sleep(0.5) # simulate slow work
42
})
cat('Future created, doing other work...\n')
# Retrieve the result (blocks until done)
result <- value(f)
cat('Result:', result, '\n')plan(): scelta del backend
plan() imposta la strategia di esecuzione per tutti i future successivi. Le strategie più comuni sono sequential (predefinita, a thread singolo), multisession (più sessioni R, funziona ovunque) e multicore (basata su fork, solo Unix/macOS).
library(future)
# Default: sequential (no parallelism)
plan(sequential)
cat('Strategy:', class(plan())[1], '\n')
# Parallel with separate R sessions (works on Windows too)
plan(multisession, workers = 4)
cat('Strategy:', class(plan())[1], '\n')
# Forking (Unix/macOS only, lower overhead)
if (.Platform$OS.type != 'windows') {
plan(multicore, workers = 4)
cat('Strategy:', class(plan())[1], '\n')
}
# Reset to sequential
plan(sequential)value(): attesa dei risultati
value(f) blocca il processo corrente finché il calcolo del future non termina, quindi restituisce il risultato. Se il future ha generato un errore, value() lo genera nuovamente nella sessione chiamante.
library(future)
plan(multisession, workers = 2)
# Launch two slow tasks concurrently
f1 <- future({ Sys.sleep(0.3); sum(1:1000) })
f2 <- future({ Sys.sleep(0.3); prod(1:10) })
# Both run in parallel; total time ~ 0.3s not 0.6s
start <- proc.time()[['elapsed']]
v1 <- value(f1)
v2 <- value(f2)
elapsed <- proc.time()[['elapsed']] - start
cat('v1:', v1, ' v2:', v2, '\n')
cat('Elapsed:', round(elapsed, 2), 's\n')
plan(sequential)L'operatore %<-%
L'operatore %<-% è una forma abbreviata di future() + value() lazy. Ha l'aspetto di una normale assegnazione, ma il membro destro viene eseguito in modo asincrono. Il valore viene recuperato la prima volta che si accede alla variabile.
library(future)
plan(multisession, workers = 2)
# %<-% starts the computation immediately in the background
x %<-% {
Sys.sleep(0.3)
rnorm(5, mean = 10)
}
y %<-% {
Sys.sleep(0.3)
runif(5, min = 1, max = 5)
}
cat('Both running in background...\n')
# Accessing x or y here blocks until ready
cat('x:', round(x, 2), '\n')
cat('y:', round(y, 2), '\n')
plan(sequential)Rilevamento automatico delle variabili globali
Una delle funzionalità più potenti di future è il rilevamento delle variabili globali: individua automaticamente le variabili a cui fa riferimento il codice del future nell'ambiente chiamante e le invia al worker, senza bisogno di chiamare manualmente clusterExport().
library(future)
plan(multisession, workers = 2)
# These globals are auto-detected and sent to the worker
threshold <- 50
multiplier <- 3
f <- future({
x <- threshold * multiplier # uses both globals
x + 1
})
cat('Result:', value(f), '\n') # 151
# Inspect which globals were identified
future_obj <- future({
threshold + multiplier
}, lazy = TRUE)
cat('Globals found:', paste(names(future::getGlobalsAndPackages(future_obj)$globals), collapse = ', '), '\n')
plan(sequential)future_options: configurazione del comportamento
Le future.options (accessibili tramite gli argomenti di options() o future::plan()) controllano le impostazioni globali: la quantità massima di memoria consentita per ogni future, la strategia di rilevamento delle variabili globali e il comportamento dei timeout.
library(future)
# Cap memory per future at 500 MB
options(future.globals.maxSize = 500 * 1024^2) # bytes
# Disable automatic global detection (manual control)
options(future.globals.onReference = 'error')
# Inspect current settings
cat('Max globals size (MB):',
getOption('future.globals.maxSize') / 1024^2, '\n')
# Restore defaults
options(future.globals.maxSize = 500 * 1024^2)
options(future.globals.onReference = NULL)
plan(multisession, workers = 2)
# Large object: you'd get an error if it exceeds the cap
big_vec <- 1:1e5 # small enough
f <- future(sum(big_vec))
cat('Sum:', value(f), '\n')
plan(sequential)Future annidati
I future possono essere annidati: un future può creare a sua volta future interni. Per impostazione predefinita, i future interni vengono eseguiti in sequenza, a meno che non si imposti un piano annidato con plan(list(...)). Questo è utile per il parallelismo a due livelli.
library(future)
# Two-level parallelism: outer uses multisession, inner sequential
plan(list(multisession, sequential))
outer_futures <- lapply(1:3, function(i) {
future({
# Each outer worker runs its own sequential inner work
inner <- lapply(1:4, function(j) i * j)
unlist(inner)
})
})
results <- lapply(outer_futures, value)
for (i in seq_along(results)) {
cat('Outer', i, ':', results[[i]], '\n')
}
plan(sequential)Gestione degli errori con i future
Quando un calcolo eseguito da un future genera un errore, value() lo genera nuovamente. Racchiuda value() in tryCatch() per gestire gli errori dei singoli future senza interrompere l'intera pipeline.
library(future)
plan(multisession, workers = 2)
# This future will error
bad_future <- future(log(-1, base = 'oops')) # invalid arg
good_future <- future(sqrt(144))
# Handle errors gracefully
bad_result <- tryCatch(
value(bad_future),
error = function(e) {
cat('Caught error:', conditionMessage(e), '\n')
NA
}
)
good_result <- value(good_future)
cat('bad_result:', bad_result, '\n')
cat('good_result:', good_result, '\n')
plan(sequential)Verifica dello stato di un future
resolved(f) restituisce TRUE se un future è terminato, senza bloccare l'esecuzione. Questo consente di verificare periodicamente il completamento e svolgere attività utili durante l'attesa, creando un ciclo di verifica non bloccante.
library(future)
plan(multisession, workers = 2)
f <- future({
Sys.sleep(0.5)
'done'
})
# Poll without blocking
counter <- 0
while (!resolved(f)) {
counter <- counter + 1
Sys.sleep(0.1)
cat('Polling... (', counter, ')\n')
}
cat('Future resolved! Result:', value(f), '\n')
cat('Polled', counter, 'times\n')
plan(sequential)Combinare future con lapply
Combini lapply() con future() per distribuire N attività e lapply() con value() per raccogliere i risultati. Questo schema offre un controllo esplicito sul momento di avvio di ciascun future.
library(future)
plan(multisession, workers = 4)
# Fan out: create all futures
params <- list(
list(n = 1000, mean = 0),
list(n = 1000, mean = 5),
list(n = 1000, mean = 10),
list(n = 1000, mean = -3)
)
futures <- lapply(params, function(p) {
future({
x <- rnorm(p$n, mean = p$mean)
list(mean = mean(x), sd = sd(x))
})
})
# Fan in: collect results
results <- lapply(futures, value)
for (i in seq_along(results)) {
cat('Param mean', params[[i]]$mean,
'-> observed mean:', round(results[[i]]$mean, 3), '\n')
}
plan(sequential)Caso d'uso reale: valutazione dei fold della validazione incrociata
La validazione incrociata è un problema parallelizzabile in modo semplice: ogni fold è indipendente. Usando i future, è possibile valutare simultaneamente tutti i K fold, riducendo significativamente il tempo trascorso per i modelli più costosi.
library(future)
plan(multisession, workers = 4)
set.seed(42)
data <- data.frame(x = rnorm(200), y = rnorm(200))
fold_ids <- sample(rep(1:4, 50))
# Launch all folds in parallel
fold_futures <- lapply(1:4, function(k) {
future({
train <- data[fold_ids != k, ]
test <- data[fold_ids == k, ]
fit <- lm(y ~ x, data = train)
preds <- predict(fit, newdata = test)
rmse <- sqrt(mean((test$y - preds)^2))
rmse
})
})
rmses <- unlist(lapply(fold_futures, value))
cat('Fold RMSEs:', round(rmses, 4), '\n')
cat('Mean RMSE:', round(mean(rmses), 4), '\n')
plan(sequential)Verifica rapida
Desidera eseguire codice parallelo che funzioni su Windows e macOS. Quale strategia di plan() dovrebbe scegliere?
Riepilogo: framework future
Punti chiave:
future({expr})esegue un'espressione in modo asincrono;value(f)recupera il risultato%<-%è una forma abbreviata: un'assegnazione con valutazione lazy del futureplan(multisession)per la compatibilità tra piattaforme;plan(multicore)per il fork su Unix/macOS- Le variabili globali vengono rilevate automaticamente e inviate ai worker, senza bisogno di
clusterExport() resolved(f)verifica il completamento senza bloccare l'esecuzione- Racchiuda
value()intryCatch()per pipeline resilienti agli errori - Chiami sempre
plan(sequential)oplan()per ripristinare la configurazione al termine
library(future)
plan(multisession, workers = 2)
# Concise pattern: fan-out then fan-in
task <- function(i) future({ i^2 + i })
results <- lapply(1:6, task)
cat(unlist(lapply(results, value)), '\n') # 2 6 12 20 30 42
plan(sequential)Domande Frequenti
La lezione «Il framework future» è gratuita?
Sì — il testo completo di «Il framework future» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso R Academy, passa a CoddyKit PRO. Il corso R Academy include 4 lezioni in totale.
Cosa imparerò in «Il framework future»?
Utilizzi plan(multisession) e future() per un'elaborazione parallela asincrona e portabile Eserciti R Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare R Academy?
Non è richiesta alcuna esperienza precedente. R Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Il framework future»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione R Academy?
Sì. Ogni lezione R Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Pacchetto parallel e detectCores()
- Il framework future
- furrr: operazioni parallele di purrr
- Debugging e bilanciamento del carico nel codice parallelo