R Academy · Aula

O framework future

Use plan(multisession) e future() para paralelismo assíncrono e portátil.

Aula 2 de 413 etapas

O framework future é uma aula grátis de R Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de R Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de R Academy inclui 4 aulas no total.

O que é o pacote future?

O pacote future fornece uma API unificada e de alto nível para programação assíncrona e paralela em R. Um future é um espaço reservado para um valor que estará disponível mais tarde — possivelmente calculado em outro núcleo ou máquina.

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(): Escolhendo um mecanismo

plan() define a estratégia de execução para todos os futures subsequentes. As estratégias mais comuns são sequential (padrão, thread única), multisession (várias sessões do R, funciona em qualquer lugar) e multicore (bifurcação de processos, apenas em 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(): Aguardando resultados

value(f) bloqueia o processo atual até que o cálculo do future seja concluído e então retorna o resultado. Se o future gerar um erro, value() o lança novamente na sessão chamadora.

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)

O operador %<-%

O operador %<-% é um açúcar sintático para future() + value() preguiçoso. Ele se parece com uma atribuição comum, mas o lado direito é executado de forma assíncrona. O valor é recuperado na primeira vez que a variável é acessada.

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)

Detecção automática de variáveis globais

Um dos recursos mais poderosos de future é a detecção de variáveis globais: ele encontra automaticamente as variáveis referenciadas pelo seu código future no ambiente chamador e as envia ao trabalhador — sem necessidade de clusterExport() manual.

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: Ajustando o comportamento

As future.options (acessadas por meio de argumentos de options() ou future::plan()) controlam configurações globais: a memória máxima permitida por future, a estratégia de detecção de variáveis globais e o comportamento do tempo limite.

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)

Futures aninhados

Futures podem ser aninhados: um future pode criar seus próprios futures internos. Por padrão, os futures internos são executados sequencialmente, a menos que o senhor defina um plano aninhado com plan(list(...)). Isso é útil para o paralelismo em dois níveis.

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)

Tratamento de erros com Futures

Quando um cálculo de future gera um erro, value() o lança novamente. Envolva value() em tryCatch() para tratar erros de futures individuais sem interromper todo o seu fluxo de processamento.

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)

Verificando o status do Future

resolved(f) retorna TRUE se um future tiver terminado, sem bloquear a execução. Isso permite verificar repetidamente a conclusão e realizar trabalho útil enquanto aguarda, criando um laço de verificação que não bloqueia.

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)

Combinando future com lapply

Combine lapply() com future() para distribuir N tarefas e lapply() com value() para coletar os resultados. Esse padrão oferece controle explícito sobre quando cada future começa.

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 de uso real: avaliação de partições de CV

A validação cruzada é um problema naturalmente paralelizável: cada partição é independente. Com futures, o senhor pode avaliar todas as K partições simultaneamente, reduzindo significativamente o tempo de execução de modelos dispendiosos.

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ção rápida

O senhor deseja executar código paralelo que funcione no Windows e no macOS. Qual estratégia de plan() deve escolher?

Recapitulação: estrutura future

Principais conclusões:

  • future({expr}) executa uma expressão de forma assíncrona; value(f) recupera o resultado
  • %<-% é um açúcar sintático — uma atribuição com avaliação preguiçosa de future
  • plan(multisession) para compatibilidade entre plataformas; plan(multicore) para bifurcação em Unix/macOS
  • As variáveis globais são detectadas automaticamente e enviadas aos trabalhadores — sem necessidade de clusterExport()
  • resolved(f) verifica a conclusão sem bloquear
  • Envolva value() em tryCatch() para criar fluxos de processamento resistentes a erros
  • Sempre chame plan(sequential) ou plan() para redefinir a configuração ao terminar
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)
Grátis para começar

Aprenda R com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
43
Aulas
159

Perguntas Frequentes

A aula “O framework future” é grátis?

Sim — o texto completo de “O framework future” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de R Academy, atualize para CoddyKit PRO. O curso de R Academy inclui 4 aulas no total.

O que vou aprender em “O framework future”?

Use plan(multisession) e future() para paralelismo assíncrono e portátil. Você pratica R Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar R Academy?

Nenhuma experiência prévia é necessária. R Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “O framework future”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de R Academy?

Sim. Cada aula de R Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Pacote parallel e detectCores()
  2. O framework future
  3. furrr: operações paralelas com purrr
  4. Depuração e balanceamento de carga de código paralelo
← Voltar para R Academy