furrr: การดำเนินการ purrr แบบขนาน
แทนที่ map() ได้ทันทีด้วย future_map() เพื่อทำงานแบบขนาน
furrr: การดำเนินการ purrr แบบขนาน เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน R Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน
furrr: purrr แบบขนาน
furrr (future + purrr) มีฟังก์ชันแบบขนานที่ใช้แทนฟังก์ชัน purrr::map_*() ทั้งหมดได้โดยตรง เพียงเปลี่ยน map() เป็น future_map() หลังจากกำหนด plan() แล้วกระบวนการของคุณจะทำงานแบบขนานโดยไม่ต้องเปลี่ยนโครงสร้าง
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)
การระบุ workers อย่างชัดเจนใน plan() จะจำกัดจำนวนเซสชัน R ที่ทำงานแบบขนาน สำหรับงานที่ใช้ CPU การตั้งค่า workers = parallel::detectCores() - 1 เป็นแนวทางที่ใช้กันทั่วไป เพื่อเหลือแกนประมวลผลหนึ่งแกนไว้ให้ OS
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 และรูปแบบระบุชนิด
เช่นเดียวกับ purrr แพ็กเกจ furrr มีรูปแบบที่ระบุชนิด ได้แก่ future_map_dbl(), future_map_int(), future_map_chr() และ future_map_lgl() ฟังก์ชันเหล่านี้บังคับชนิดของค่าที่ส่งคืน และส่งคืนเวกเตอร์อะตอมแทนที่จะเป็นรายการ
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: การแมปอินพุตสองชุด
future_map2(.x, .y, .f) วนซ้ำรายการหรือเวกเตอร์สองชุดแบบขนาน โดยส่งคู่ข้อมูลที่สอดคล้องกันไปยังฟังก์ชัน ซึ่งเป็นรูปแบบแบบขนานของ 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: การควบคุมพฤติกรรม
ส่ง furrr_options() เป็นอาร์กิวเมนต์ .options ให้กับการเรียก future_map_*() ใดก็ได้ การตั้งค่าที่สำคัญที่สุดคือ seed = TRUE ซึ่งเปิดใช้ตัวสร้างเลขสุ่มแบบขนาน L'Ecuyer-CMRG เพื่อให้ได้ตัวเลขสุ่มที่ทำซ้ำได้ในตัวทำงานต่าง ๆ
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)การรายงานความคืบหน้าด้วย progressr
แพ็กเกจ progressr ทำงานร่วมกับ furrr เพื่อแสดงแถบความคืบหน้าระหว่างการทำงานแบบขนาน ให้ครอบโค้ดด้วย with_progress() และสร้าง progressor() ภายในฟังก์ชันที่ใช้แมป
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)ตัวแปรโกลบอลใน furrr
เช่นเดียวกับแพ็กเกจ future แพ็กเกจ furrr จะตรวจหาตัวแปรโกลบอลที่ถูกอ้างอิงภายใน .f โดยอัตโนมัติ คุณสามารถกำหนดทับได้ด้วย furrr_options(globals = c('var1', 'var2')) เพื่อระบุว่าต้องการส่งตัวแปรโกลบอลใดบ้าง ซึ่งช่วยลดค่าใช้จ่ายแฝงสำหรับสภาพแวดล้อมขนาดใหญ่
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: การแมปอาร์กิวเมนต์หลายชุด
future_pmap(.l, .f) เป็นเวอร์ชันแบบขนานของ purrr::pmap() ฟังก์ชันนี้รับรายการเวกเตอร์หรือรายการ และส่งแถวที่สอดคล้องกันไปเป็นอาร์กิวเมนต์ที่มีชื่อ ทำให้คำนวณแบบขนานข้ามชุดค่าพารามิเตอร์หลายชุดได้
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)การเปรียบเทียบประสิทธิภาพ furrr กับ purrr
ประโยชน์จากการประมวลผลแบบขนานจะเพิ่มขึ้นตามขนาดของงาน สำหรับการดำเนินการง่าย ๆ (x^2) ค่าใช้จ่ายแฝงจะมีสัดส่วนสูงกว่า ทำให้การทำงานตามลำดับเร็วกว่า แต่สำหรับงานหนัก เช่น การปรับแบบจำลองจำนวนมาก การทำงานแบบขนานช่วยประหยัดเวลาได้มาก
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)การจัดการข้อผิดพลาดใน future_map
หากการคำนวณของสมาชิกใดทำให้เกิดข้อผิดพลาด future_map() จะหยุดและส่งข้อผิดพลาดนั้นซ้ำ หากต้องการทำงานต่อแม้เกิดข้อผิดพลาด ให้ใช้ตัวห่อ purrr::safely() หรือ purrr::possibly() ครอบฟังก์ชันของคุณ
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)กระบวนการ furrr ในทางปฏิบัติ
นี่คือตัวอย่างกระบวนการตั้งแต่ต้นจนจบ: โหลดข้อมูล ปรับแบบจำลองหลายรายการแบบขนานโดยใช้ค่าเริ่มต้นที่ทำซ้ำได้ ดึงตัวชี้วัดประสิทธิภาพ และเลือกแบบจำลองที่ดีที่สุด ทั้งหมดนี้โดยใช้รูปแบบการเขียนของ 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)ตรวจสอบความเข้าใจอย่างรวดเร็ว
คุณต้องการให้ได้ตัวเลขสุ่มที่ทำซ้ำได้จากการเรียก future_map() แบบขนาน ควรใช้การตั้งค่าใดของ furrr_options()
สรุป: แพ็กเกจ furrr
ประเด็นสำคัญ:
furrrเป็นตัวแทนแบบขนานของpurrrที่ใช้แทนกันได้โดยตรง เพียงเปลี่ยนmapเป็นfuture_map- กำหนดแบ็กเอนด์ก่อนด้วย
plan(multisession, workers = n) - รูปแบบระบุชนิด:
future_map_dbl(),future_map_int(),future_map_chr() - ใช้
future_map2()และfuture_pmap()สำหรับการแมปแบบขนานที่มีอินพุตหลายชุด - ใช้
furrr_options(seed = 42L)เพื่อให้ตัวสร้างเลขสุ่มแบบขนานทำซ้ำได้ - ผสานการทำงานกับ
progressrเพื่อแสดงแถบความคืบหน้าระหว่างงานแบบขนานที่ใช้เวลานาน - ใช้
purrr::safely()ภายในfuture_map()เพื่อให้กระบวนการทนต่อข้อผิดพลาด
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)คำถามที่พบบ่อย
บทเรียน “furrr: การดำเนินการ purrr แบบขนาน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “furrr: การดำเนินการ purrr แบบขนาน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “furrr: การดำเนินการ purrr แบบขนาน”
แทนที่ map() ได้ทันทีด้วย future_map() เพื่อทำงานแบบขนาน คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “furrr: การดำเนินการ purrr แบบขนาน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม
ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- แพ็กเกจ parallel และ detectCores()
- เฟรมเวิร์ก future
- furrr: การดำเนินการ purrr แบบขนาน
- การดีบักและการปรับสมดุลภาระงานของโค้ดแบบขนาน