furrr : opérations parallèles avec purrr
Remplacez directement map() par future_map() pour paralléliser instantanément vos opérations.
furrr : opérations parallèles avec purrr est une leçon R Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage R Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours R Academy comprend 4 leçons au total.
furrr : purrr en parallèle
furrr (future + purrr) fournit des remplacements parallèles directs pour toutes les fonctions purrr::map_*(). Il suffit de remplacer map() par future_map() après avoir défini un plan() pour exécuter votre chaîne de traitement en parallèle, sans modifier sa structure.
library(furrr)
library(future)
# Set up parallel workers
plan(multisession, workers = 4)
# Sequential (purrr)
# result <- purrr::map(1:8, ~.x^2)
# Parallel (furrr) — identical API
result <- future_map(1:8, ~.x^2)
cat(unlist(result), '\n') # 1 4 9 16 25 36 49 64
plan(sequential)plan(multisession, workers = 4)
La spécification explicite de workers dans plan() limite le nombre de sessions R parallèles. Pour les tâches limitées par le processeur, workers = parallel::detectCores() - 1 est une convention courante qui laisse un cœur au système d’exploitation.
library(furrr)
library(future)
library(parallel)
# Explicit worker count
n_workers <- max(1, detectCores() - 1)
plan(multisession, workers = n_workers)
cat('Active workers:', nbrOfWorkers(), '\n')
cat('Strategy:', class(plan())[1], '\n')
# Run a simple parallel task
results <- future_map_dbl(1:8, ~sqrt(.x))
cat(round(results, 3), '\n')
plan(sequential)future_map_dbl et variantes typées
Comme purrr, furrr fournit des variantes typées : future_map_dbl(), future_map_int(), future_map_chr() et future_map_lgl(). Elles imposent le type de retour et renvoient un vecteur atomique plutôt qu’une liste.
library(furrr)
plan(multisession, workers = 2)
# Returns a numeric vector
square_roots <- future_map_dbl(1:6, ~sqrt(.x))
cat('dbl:', round(square_roots, 3), '\n')
# Returns an integer vector
counts <- future_map_int(list('hello', 'world', 'R'), nchar)
cat('int:', counts, '\n')
# Returns a character vector
formatted <- future_map_chr(c(1.23, 4.56, 7.89), ~sprintf('%.1f', .x))
cat('chr:', formatted, '\n')
# Returns a logical vector
positive <- future_map_lgl(-3:3, ~.x > 0)
cat('lgl:', positive, '\n')
plan(sequential)future_map2 : appliquer une fonction à deux entrées
future_map2(.x, .y, .f) parcourt en parallèle deux listes ou vecteurs et transmet à la fonction les paires correspondantes. C’est l’équivalent parallèle de purrr::map2().
library(furrr)
plan(multisession, workers = 2)
# Simulate different sample sizes and means
sizes <- c(100, 200, 300, 400)
means <- c(0, 5, -3, 10)
# future_map2 passes each (n, mu) pair to rnorm
samples <- future_map2(sizes, means, ~rnorm(.x, mean = .y))
# Verify: each element has the expected length and approximate mean
for (i in seq_along(samples)) {
cat('n=', sizes[i], 'target_mean=', means[i],
'observed_mean=', round(mean(samples[[i]]), 2), '\n')
}
plan(sequential)furrr_options : contrôler le comportement
furrr_options() est fourni comme argument .options à tout appel future_map_*(). Le paramètre le plus important est seed = TRUE, qui active le générateur aléatoire parallèle L’Ecuyer-CMRG afin d’obtenir des nombres aléatoires reproductibles entre les processus de travail.
library(furrr)
plan(multisession, workers = 2)
# Without seed: results differ each run
r1 <- future_map_dbl(1:4, ~rnorm(1))
r2 <- future_map_dbl(1:4, ~rnorm(1))
cat('Without seed - same?', identical(r1, r2), '\n')
# With seed: reproducible
opts <- furrr_options(seed = 42L)
r3 <- future_map_dbl(1:4, ~rnorm(1), .options = opts)
r4 <- future_map_dbl(1:4, ~rnorm(1), .options = opts)
cat('With seed - same?', identical(r3, r4), '\n')
cat('r3:', round(r3, 4), '\n')
plan(sequential)Afficher la progression avec progressr
Le package progressr s’intègre à furrr pour afficher des barres de progression pendant l’exécution parallèle. Entourez votre code de with_progress() et créez un progressor() dans la fonction appliquée.
library(furrr)
library(progressr)
plan(multisession, workers = 2)
# Enable progress reporting
handlers(global = TRUE) # show progress in console
with_progress({
p <- progressor(steps = 8)
results <- future_map(1:8, function(i) {
p() # increment the progress bar
Sys.sleep(0.1)
i^2
})
})
cat('Results:', unlist(results), '\n')
plan(sequential)Variables globales dans furrr
Comme le package future, furrr détecte automatiquement les variables globales référencées dans .f. Vous pouvez remplacer ce comportement avec furrr_options(globals = c('var1', 'var2')) pour spécifier précisément les variables globales à envoyer, et ainsi réduire les coûts liés aux grands environnements.
library(furrr)
plan(multisession, workers = 2)
# Global variables auto-detected
scale_factor <- 10
offset <- 5
result <- future_map_dbl(
1:6,
function(x) x * scale_factor + offset
)
cat(result, '\n') # 15 25 35 45 55 65
# Explicit globals control
opts <- furrr_options(
globals = c('scale_factor', 'offset'),
seed = FALSE
)
result2 <- future_map_dbl(
1:6,
function(x) x * scale_factor + offset,
.options = opts
)
cat('Manual globals:', result2, '\n')
plan(sequential)future_pmap : appliquer une fonction à plusieurs arguments
future_pmap(.l, .f) est la version parallèle de purrr::pmap(). Elle accepte une liste de vecteurs ou de listes et transmet les lignes correspondantes comme arguments nommés, ce qui permet d’effectuer des calculs en parallèle pour plusieurs combinaisons de paramètres.
library(furrr)
plan(multisession, workers = 2)
# Parameter grid
params <- list(
n = c(50, 100, 150, 200),
mean = c(0, 1, 2, 3),
sd = c(1, 2, 1, 0.5)
)
# future_pmap passes each row as arguments to rnorm
samples <- future_pmap(params, function(n, mean, sd) {
x <- rnorm(n, mean = mean, sd = sd)
c(obs_mean = round(mean(x), 3), obs_sd = round(sd(x), 3))
})
for (i in seq_along(samples)) {
cat('n=', params$n[i], ':', samples[[i]], '\n')
}
plan(sequential)Comparer les performances de furrr et purrr
Les bénéfices du parallélisme augmentent avec le coût des tâches. Pour des opérations triviales (x^2), les coûts supplémentaires prédominent et l’exécution séquentielle est plus rapide. Pour des tâches lourdes, comme l’ajustement de nombreux modèles, le parallélisme fait gagner beaucoup de temps.
library(furrr)
library(purrr)
plan(multisession, workers = 4)
# Heavy task: bootstrap a linear model 100 times
heavy <- function(i) {
n <- 200
df <- data.frame(x = rnorm(n), y = rnorm(n))
coef(lm(y ~ x, data = df))[['x']]
}
seq_time <- system.time(map_dbl(1:40, heavy))[['elapsed']]
par_time <- system.time(
future_map_dbl(1:40, heavy, .options = furrr_options(seed = TRUE))
)[['elapsed']]
cat('Sequential:', round(seq_time, 2), 's\n')
cat('Parallel: ', round(par_time, 2), 's\n')
cat('Speedup: ', round(seq_time / max(par_time, 0.001), 2), 'x\n')
plan(sequential)Gestion des erreurs dans future_map
Si le calcul d’un élément génère une erreur, future_map() s’arrête et la relance. Pour continuer malgré les erreurs, utilisez les enveloppes purrr::safely() ou purrr::possibly() autour de votre fonction.
library(furrr)
library(purrr)
plan(multisession, workers = 2)
# Wrap with safely() to capture errors as results
safe_log <- safely(log, otherwise = NA_real_)
inputs <- list(10, -1, 100, 'text', 0.5)
results <- future_map(inputs, safe_log)
for (i in seq_along(results)) {
if (is.null(results[[i]]$error)) {
cat('Input', i, '-> result:', round(results[[i]]$result, 4), '\n')
} else {
cat('Input', i, '-> error:', conditionMessage(results[[i]]$error), '\n')
}
}
plan(sequential)Chaîne de traitement furrr concrète
Voici une chaîne de traitement complète de bout en bout : charger les données, ajuster plusieurs modèles en parallèle avec des valeurs initiales reproductibles, extraire les mesures de performance et sélectionner le meilleur modèle, le tout en utilisant l’approche furrr.
library(furrr)
library(purrr)
plan(multisession, workers = 4)
set.seed(1)
n <- 300
df <- data.frame(
x1 = rnorm(n), x2 = rnorm(n), x3 = rnorm(n),
y = rnorm(n)
)
formulas <- list(
y ~ x1,
y ~ x1 + x2,
y ~ x1 + x2 + x3,
y ~ x1 * x2
)
# Fit all models in parallel
models <- future_map(
formulas,
~lm(.x, data = df),
.options = furrr_options(seed = FALSE)
)
# Extract adjusted R-squared
adj_r2 <- map_dbl(models, ~summary(.x)$adj.r.squared)
cat('Adjusted R2 per model:',
paste(round(adj_r2, 4), collapse = ', '), '\n')
cat('Best model:', which.max(adj_r2), '\n')
plan(sequential)Vérification rapide
Vous souhaitez obtenir des nombres aléatoires reproductibles lors de plusieurs appels parallèles à future_map(). Quel paramètre de furrr_options() permet cela ?
Récapitulatif : package furrr
À retenir :
furrrremplace directementpurrrpour l’exécution parallèle : remplacez simplementmapparfuture_map- Définissez d’abord un moteur avec
plan(multisession, workers = n) - Variantes typées :
future_map_dbl(),future_map_int(),future_map_chr() future_map2()etfuture_pmap()permettent l’application parallèle à plusieurs entréesfurrr_options(seed = 42L)assure un générateur aléatoire parallèle reproductible- Intégrez
progressrpour afficher des barres de progression lors des longues tâches parallèles - Utilisez
purrr::safely()dansfuture_map()pour des chaînes de traitement résistantes aux erreurs
library(furrr)
plan(multisession, workers = 2)
results <- future_map_dbl(
1:6,
~.x^2 + sqrt(.x),
.options = furrr_options(seed = TRUE)
)
cat(round(results, 3), '\n')
plan(sequential)Questions Fréquemment Posées
La leçon « furrr : opérations parallèles avec purrr » est-elle gratuite ?
Oui — le texte complet de « furrr : opérations parallèles avec purrr » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours R Academy, passe à CoddyKit PRO. Le cours R Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « furrr : opérations parallèles avec purrr » ?
Remplacez directement map() par future_map() pour paralléliser instantanément vos opérations. Tu pratiques R Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer R Academy ?
Aucune expérience préalable n'est requise. R Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « furrr : opérations parallèles avec purrr » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon R Academy ?
Oui. Chaque leçon R Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Paquet parallel et detectCores()
- Le cadriciel future
- furrr : opérations parallèles avec purrr
- Déboguer et équilibrer la charge du code parallèle