0Pricing
R Academy · บทเรียน

เฟรมเวิร์ก future

ใช้ plan(multisession) และ future() เพื่อการประมวลผลแบบขนานที่ไม่ต้องรอและพกพาได้

เฟรมเวิร์ก future เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน R Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

แพ็กเกจ future คืออะไร

แพ็กเกจ future มีส่วนต่อประสานการเขียนโปรแกรมระดับสูงแบบรวมเป็นหนึ่งเดียว สำหรับการเขียนโปรแกรมแบบอะซิงโครนัสและแบบขนานใน R 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(...)) วิธีนี้มีประโยชน์สำหรับการประมวลผลแบบขนานสองระดับ

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() จะส่งข้อผิดพลาดนั้นซ้ำ ให้ครอบ value() ด้วย tryCatch() เพื่อจัดการข้อผิดพลาดของ future แต่ละรายการโดยไม่หยุดกระบวนการทั้งหมดของคุณ

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) จะส่งคืนค่า TRUE หาก future ทำงานเสร็จแล้ว โดยไม่หยุดรอ วิธีนี้ช่วยให้คุณตรวจสอบการเสร็จสิ้นเป็นระยะและทำงานที่เป็นประโยชน์ระหว่างรอได้ ทำให้สร้างลูปตรวจสอบแบบไม่บล็อกได้

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) เมื่อต้องการรองรับหลายแพลตฟอร์ม และใช้ plan(multicore) สำหรับการแยกกระบวนการบน Unix/macOS
  • ตัวแปรโกลบอลจะถูกตรวจหาและส่งไปยังตัวทำงานโดยอัตโนมัติ จึงไม่จำเป็นต้องใช้ 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” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “เฟรมเวิร์ก future”

ใช้ plan(multisession) และ future() เพื่อการประมวลผลแบบขนานที่ไม่ต้องรอและพกพาได้ คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “เฟรมเวิร์ก future” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม

ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. แพ็กเกจ parallel และ detectCores()
  2. เฟรมเวิร์ก future
  3. furrr: การดำเนินการ purrr แบบขนาน
  4. การดีบักและการปรับสมดุลภาระงานของโค้ดแบบขนาน
← กลับไปที่ R Academy