furrr: عمليات purrr المتوازية
استبدل map() مباشرةً بـ future_map() لإجراء العمليات بالتوازي فورًا
furrr: عمليات purrr المتوازية درس مجاني في R Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 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 المتوازية. وبالنسبة إلى المهام المرتبطة بالمعالج، من الشائع استخدام workers = parallel::detectCores() - 1 لترك نواة واحدة لنظام التشغيل.
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 المتوازية» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة R Academy، انتقل إلى CoddyKit PRO. تتضمن دورة R Academy 4 دروس في المجموع.
ماذا ستتعلم في «furrr: عمليات purrr المتوازية»؟
استبدل map() مباشرةً بـ future_map() لإجراء العمليات بالتوازي فورًا تتمرن على R Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ R Academy؟
لا تُشترط خبرة سابقة. R Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «furrr: عمليات purrr المتوازية»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس R Academy هذا؟
نعم. كل درس في R Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- حزمة parallel وdetectCores()
- إطار عمل future
- furrr: عمليات purrr المتوازية
- تصحيح أخطاء التعليمات البرمجية المتوازية وموازنة الأحمال