R Academy · Lekcja

Framework future

Używaj plan(multisession) i future() do asynchronicznego, przenośnego przetwarzania równoległego.

Lekcja 2 z 413 kroki

Framework future to bezpłatna lekcja R Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej R Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs R Academy zawiera 4 lekcji w sumie.

Czym jest pakiet future?

Pakiet future udostępnia ujednolicone, wysokopoziomowe API do programowania asynchronicznego i równoległego w języku R. Future to symbol zastępczy wartości, która będzie dostępna później — może zostać obliczona na innym rdzeniu lub komputerze.

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(): wybór backendu

plan() ustawia strategię wykonywania dla wszystkich kolejnych obiektów future. Najczęściej używane strategie to sequential (domyślna, jednowątkowa), multisession (wiele sesji R, działa wszędzie) oraz multicore (rozgałęzianie procesów, tylko 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(): oczekiwanie na wyniki

value(f) blokuje bieżący proces do momentu zakończenia obliczeń future, a następnie zwraca wynik. Jeśli w obiekcie future wystąpił błąd, value() zgłasza go ponownie w sesji wywołującej.

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)

Operator %<-%

Operator %<-% jest cukrem składniowym dla połączenia future() i leniwej funkcji value(). Wygląda jak zwykłe przypisanie, ale prawa strona jest wykonywana asynchronicznie. Wartość jest pobierana przy pierwszym odwołaniu do zmiennej.

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)

Automatyczne wykrywanie zmiennych globalnych

Jedną z najbardziej zaawansowanych funkcji pakietu future jest wykrywanie zmiennych globalnych: automatycznie wyszukuje zmienne, do których odwołuje się kod future w środowisku wywołującym, i przesyła je do procesu roboczego — nie jest potrzebne ręczne użycie 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: dostosowywanie działania

Opcje future.options (dostępne za pośrednictwem argumentów funkcji options() lub future::plan()) sterują ustawieniami globalnymi: maksymalną dozwoloną pamięcią dla każdego obiektu future, strategią wykrywania zmiennych globalnych oraz działaniem limitu czasu.

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)

Zagnieżdżone obiekty future

Obiekty future można zagnieżdżać: obiekt future może samodzielnie tworzyć wewnętrzne obiekty future. Domyślnie wewnętrzne obiekty future są wykonywane sekwencyjnie, chyba że ustawią Państwo zagnieżdżony plan za pomocą plan(list(...)). Jest to przydatne w przypadku dwupoziomowego przetwarzania równoległego.

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)

Obsługa błędów w obiektach future

Gdy podczas obliczeń future wystąpi błąd, value() zgłasza go ponownie. Proszę opakować value() w tryCatch(), aby obsługiwać błędy poszczególnych obiektów future bez zatrzymywania całego potoku.

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)

Sprawdzanie stanu obiektu future

resolved(f) zwraca TRUE, jeśli obiekt future zakończył działanie, nie blokując bieżącego procesu. Umożliwia to sprawdzanie stanu ukończenia i wykonywanie przydatnej pracy podczas oczekiwania, czyli utworzenie nieblokującej pętli sprawdzającej.

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)

Łączenie future z lapply

Proszę połączyć lapply() z future(), aby rozdzielić N zadań, a następnie użyć lapply() z value() do zebrania wyników. Ten wzorzec zapewnia jawą kontrolę nad momentem uruchomienia każdego obiektu 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)

Praktyczny przypadek: ocena foldów walidacji krzyżowej

Walidacja krzyżowa jest problemem doskonale nadającym się do przetwarzania równoległego: każdy fold jest niezależny. Dzięki obiektom future mogą Państwo oceniać wszystkie K foldów jednocześnie, znacznie skracając czas rzeczywisty wykonywania kosztownych modeli.

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)

Szybkie sprawdzenie

Chcą Państwo uruchomić kod równoległy działający zarówno w systemie Windows, jak i macOS. Którą strategię funkcji plan() należy wybrać?

Podsumowanie: framework future

Najważniejsze informacje:

  • future({expr}) wykonuje wyrażenie asynchronicznie, a value(f) pobiera wynik
  • %<-% jest cukrem składniowym — przypisaniem z leniwą ewaluacją future
  • plan(multisession) służy do pracy między platformami, a plan(multicore) do rozgałęziania procesów w systemach Unix/macOS
  • Zmienne globalne są wykrywane automatycznie i przesyłane do procesów roboczych — nie trzeba używać clusterExport()
  • resolved(f) sprawdza ukończenie bez blokowania procesu
  • Proszę opakować value() w tryCatch(), aby tworzyć potoki odporne na błędy
  • Po zakończeniu należy zawsze wywołać plan(sequential) lub plan(), aby zresetować ustawienia
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)
Bezpłatny start

Ucz się R dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
43
Lekcje
159

Często zadawane pytania

Czy lekcja „Framework future” jest bezpłatna?

Tak — pełny tekst „Framework future” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu R Academy, przejdź na CoddyKit PRO. Kurs R Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Framework future”?

Używaj plan(multisession) i future() do asynchronicznego, przenośnego przetwarzania równoległego. Ćwiczysz R Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć R Academy?

Nie wymagamy żadnego doświadczenia. R Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Framework future”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji R Academy?

Tak. Każda lekcja R Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Pakiet parallel i detectCores()
  2. Framework future
  3. furrr: równoległe operacje purrr
  4. Debugowanie i równoważenie obciążenia kodu równoległego
← Powrót do R Academy