0Pricing
R Academy · 강의

future 프레임워크

plan(multisession)과 future()를 사용해 비동기적이고 이식 가능한 병렬 처리를 구현합니다.

future 프레임워크은(는) CoddyKit의 무료 R Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 R Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

future 패키지란 무엇인가요

future 패키지는 R에서 비동기 및 병렬 프로그래밍을 위한 통합된 고수준 API를 제공합니다. future는 나중에 사용할 수 있게 될 값을 담아 두는 자리 표시자입니다. 이 값은 다른 코어나 컴퓨터에서 계산될 수도 있습니다.

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(): 백엔드 선택

plan()은 이후에 생성되는 모든 future의 실행 전략을 설정합니다. 가장 일반적인 전략은 sequential(기본값, 단일 스레드), multisession(여러 R 세션, 어디서나 작동), multicore(포크 방식, 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(): 결과를 기다리며 차단하기

value(f)는 future의 계산이 완료될 때까지 현재 프로세스를 차단한 다음 결과를 반환합니다. future에서 오류가 발생했다면 value()는 호출한 세션에서 해당 오류를 다시 발생시킵니다.

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)

%<-% 연산자

%<-% 연산자는 future()와 지연된 value()를 결합한 문법적 편의 기능입니다. 일반적인 할당문처럼 보이지만 오른쪽 항은 비동기적으로 실행됩니다. 값은 변수를 처음 참조할 때 가져옵니다.

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)

전역 변수 자동 감지

future의 가장 강력한 기능 중 하나는 전역 변수 감지입니다. future 코드가 호출 환경에서 참조하는 변수를 자동으로 찾아 작업자에게 전송하므로, 수동으로 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: 동작 조정

future.options는 options() 또는 future::plan()의 인수를 통해 설정하며, 전역 설정을 제어합니다. 여기에는 future 하나에 허용되는 최대 메모리, 전역 변수 감지 전략, 시간 초과 동작이 포함됩니다.

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

future는 중첩할 수 있습니다. 즉, future가 내부 future를 직접 만들 수 있습니다. 기본적으로 내부 future는 순차적으로 실행되지만, plan(list(...))으로 중첩 실행 계획을 설정할 수 있습니다. 이는 2단계 병렬화에 유용합니다.

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)

future를 사용한 오류 처리

future의 계산에서 오류가 발생하면 value()가 해당 오류를 다시 발생시킵니다. 전체 파이프라인을 중단하지 않고 개별 future의 오류를 처리하려면 value()를 tryCatch()로 감싸십시오.

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)

future 상태 확인

resolved(f)는 차단하지 않고 future가 완료되었으면 TRUE를 반환합니다. 이를 이용하면 완료 여부를 확인하는 동안 다른 작업을 수행할 수 있어, 차단하지 않는 확인 반복문을 만들 수 있습니다.

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)

future와 lapply 결합하기

lapply()와 future()를 결합하면 N개의 작업을 여러 작업으로 분산할 수 있고, lapply()와 value()를 결합하면 결과를 수집할 수 있습니다. 이 패턴을 사용하면 각 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)

실제 사용 사례: CV 폴드 평가

교차 검증은 각 폴드가 서로 독립적이므로 병렬화하기 매우 좋은 문제입니다. future를 사용하면 K개의 모든 폴드를 동시에 평가하여, 계산량이 많은 모델의 실제 경과 시간을 크게 줄일 수 있습니다.

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)

빠른 확인

Windows와 macOS 모두에서 작동하는 병렬 코드를 실행하려고 합니다. 어떤 plan() 전략을 선택해야 할까요?

복습: future 프레임워크

핵심 요점:

  • future({expr})는 표현식을 비동기적으로 실행하고, value(f)는 결과를 가져옵니다
  • %<-%는 지연된 future 평가를 사용하는 할당문 형태의 문법적 편의 기능입니다
  • 플랫폼 간 호환성이 필요하면 plan(multisession)을, Unix/macOS에서 포크 방식을 사용하려면 plan(multicore)를 사용합니다
  • 전역 변수는 자동으로 감지되어 작업자에게 전송되므로 clusterExport()가 필요하지 않습니다
  • resolved(f)는 차단하지 않고 완료 여부를 확인합니다
  • 오류에 강한 파이프라인을 만들려면 value()를 tryCatch()로 감싸십시오
  • 작업이 끝나면 항상 plan(sequential) 또는 plan()을 호출하여 설정을 초기화하십시오
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)

자주 묻는 질문

“future 프레임워크” 강의는 무료인가요?

네 — “future 프레임워크” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 R Academy 강의 전체를 잠금 해제할 수 있습니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“future 프레임워크”에서 뭘 배우나요?

plan(multisession)과 future()를 사용해 비동기적이고 이식 가능한 병렬 처리를 구현합니다. 브라우저에서 직접 실행하는 실습 코드로 R Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

R Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 R Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“future 프레임워크” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 R Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 R Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. parallel 패키지와 detectCores()
  2. future 프레임워크
  3. furrr: 병렬 purrr 연산
  4. 병렬 코드 디버깅과 부하 분산
← R Academy(으)로 돌아가기