Pakiet parallel i detectCores()
Uruchamiaj klastry forkowane lub gniazdowe i rozdzielaj pracę między rdzenie procesora.
Pakiet parallel i detectCores() to bezpłatna lekcja R Academy na CoddyKit. To lekcja 1 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.
Dlaczego obliczenia równoległe?
Współczesne komputery mają wiele rdzeni CPU. Domyślnie R działa na jednym rdzeniu, pozostawiając pozostałe bezczynne. Pakiet parallel (wbudowany w R) umożliwia wykorzystanie wszystkich rdzeni w celu przyspieszenia powtarzalnych obliczeń.
# Check how many cores your machine has
library(parallel)
total_cores <- detectCores()
logical_cores <- detectCores(logical = TRUE)
physical_cores <- detectCores(logical = FALSE)
cat('Total logical cores:', total_cores, '
')
cat('Physical cores:', physical_cores, '
')makeCluster i stopCluster
makeCluster(n) uruchamia n procesów roboczych. Po zakończeniu zawsze wywołuj stopCluster(cl), aby zwolnić zasoby. Często stosuje się konwencję detectCores() - 1, pozostawiając jeden rdzeń dla systemu operacyjnego.
library(parallel)
# Spawn workers (leave 1 core for system)
n_cores <- detectCores() - 1
cl <- makeCluster(n_cores)
cat('Cluster created with', n_cores, 'workers\n')
# Always clean up!
stopCluster(cl)
cat('Cluster stopped.\n')clusterExport: udostępnianie zmiennych
Procesy robocze mają własną przestrzeń pamięci i nie widzą środowiska globalnego. Użyj clusterExport(cl, varlist), aby skopiować nazwane obiekty z procesu głównego do wszystkich procesów roboczych.
library(parallel)
cl <- makeCluster(2)
# Define a variable and a function in the master
base_value <- 100
add_base <- function(x) x + base_value
# Export them to workers
clusterExport(cl, varlist = c('base_value', 'add_base'))
# Now workers can use them
result <- parLapply(cl, 1:4, function(x) add_base(x))
cat(unlist(result), '\n') # 101 102 103 104
stopCluster(cl)clusterEvalQ: uruchamianie kodu konfiguracyjnego
clusterEvalQ(cl, expr) oblicza wyrażenie w każdym procesie roboczym — jest przydatne do ładowania pakietów lub plików pomocniczych we wszystkich węzłach przed rozpoczęciem głównych obliczeń.
library(parallel)
cl <- makeCluster(2)
# Load a package on every worker
clusterEvalQ(cl, {
library(stats)
set.seed(42) # set seed per worker
})
# Each worker can now use stats functions
result <- parLapply(cl, 1:4, function(n) rnorm(n, mean = 0, sd = 1))
result[[1]] # one random normal value
stopCluster(cl)parLapply: równoległe lapply
parLapply(cl, X, FUN) jest równoległym odpowiednikiem lapply(). Rozdziela elementy X między procesy robocze i zbiera wyniki w postaci listy. Działa na wszystkich platformach (Windows, macOS, Linux).
library(parallel)
cl <- makeCluster(2)
# Simulate slow computation: sleep 0.1s per item
clusterEvalQ(cl, Sys.sleep)
slow_square <- function(x) {
Sys.sleep(0.05)
x^2
}
clusterExport(cl, 'slow_square')
system.time(
result <- parLapply(cl, 1:8, slow_square)
)
cat(unlist(result), '\n') # 1 4 9 16 25 36 49 64
stopCluster(cl)parSapply: uproszczone wyniki
parSapply(cl, X, FUN) jest równoległą wersją sapply(). Automatycznie upraszcza wynik do wektora lub macierzy, gdy jest to możliwe, dzięki czemu sprawdza się, gdy funkcja zwraca wartość skalarną.
library(parallel)
cl <- makeCluster(2)
# parSapply returns a simplified vector
squares <- parSapply(cl, 1:10, function(x) x^2)
cat(squares, '\n') # 1 4 9 16 25 36 49 64 81 100
# Returns a matrix if FUN returns a vector of same length
stats_result <- parSapply(cl, 1:4, function(n) {
x <- rnorm(100)
c(mean = mean(x), sd = sd(x))
})
print(stats_result) # 2x4 matrix
stopCluster(cl)mclapply: równoległość oparta na forkowaniu
mclapply() używa forkowania — kopiuje bieżący proces R zamiast uruchamiać nowe procesy, dzięki czemu szybciej się uruchamia i zapewnia procesom roboczym niejawny dostęp do środowiska nadrzędnego. Działa jednak tylko w systemach Unix/macOS, a nie w systemie Windows.
library(parallel)
# mclapply: Unix/macOS only
# Workers inherit the parent environment automatically
base_value <- 42
if (.Platform$OS.type != 'windows') {
result <- mclapply(
1:8,
function(x) x * base_value, # base_value visible without export
mc.cores = 4
)
cat(unlist(result), '\n')
} else {
cat('mclapply not supported on Windows. Use parLapply instead.\n')
}Testowanie wydajności: sekwencyjnie a równolegle
Obliczenia równoległe wiążą się z narzutem: uruchomienie klastra, serializacja danych i komunikacja między procesami wymagają czasu. Zyski pojawiają się tylko wtedy, gdy obliczenia dla pojedynczego elementu są wystarczająco kosztowne, aby przewyższyć ten narzut.
library(parallel)
cl <- makeCluster(2)
# Task: compute 100 iterations of matrix multiply
heavy_task <- function(n) {
m <- matrix(rnorm(200), nrow = 100)
sum(m %*% t(m))
}
clusterExport(cl, 'heavy_task')
seq_time <- system.time(lapply(1:20, heavy_task))[['elapsed']]
par_time <- system.time(parLapply(cl, 1:20, heavy_task))[['elapsed']]
cat('Sequential:', round(seq_time, 3), 's\n')
cat('Parallel: ', round(par_time, 3), 's\n')
cat('Speedup: ', round(seq_time / par_time, 2), 'x\n')
stopCluster(cl)Inicjalizacja generatora liczb losowych w obliczeniach równoległych
Generowanie liczb losowych w obliczeniach równoległych jest trudne — każdy proces roboczy potrzebuje niezależnego i powtarzalnego strumienia. Użyj clusterSetRNGStream(cl, seed) wraz z generatorem L'Ecuyer-CMRG, aby uzyskać powtarzalną losowość równoległą.
library(parallel)
cl <- makeCluster(2)
# Set reproducible RNG streams across workers
clusterSetRNGStream(cl, iseed = 123)
# Each worker uses its own independent random stream
results1 <- parSapply(cl, 1:6, function(i) rnorm(1))
# Reset and repeat — same results
clusterSetRNGStream(cl, iseed = 123)
results2 <- parSapply(cl, 1:6, function(i) rnorm(1))
cat('Run 1:', round(results1, 4), '\n')
cat('Run 2:', round(results2, 4), '\n')
cat('Identical:', identical(results1, results2), '\n')
stopCluster(cl)Obsługa błędów w klastrach
Jeśli proces roboczy zgłosi błąd, parLapply() ponownie zgłasza go w procesie głównym. Umieść wywołania w tryCatch() wewnątrz funkcji albo użyj tryCatch() wokół całego wywołania parLapply(), aby łagodnie obsługiwać błędy.
library(parallel)
cl <- makeCluster(2)
# Wrap risky code inside the worker function
safe_log <- function(x) {
tryCatch(
log(x),
warning = function(w) NA_real_,
error = function(e) NA_real_
)
}
clusterExport(cl, 'safe_log')
# -1 produces NaN warning, 'a' produces an error
input <- list(4, 9, -1, 'a', 16)
result <- parLapply(cl, input, safe_log)
cat(unlist(result), '\n') # 1.386 2.197 NaN NA 2.773
stopCluster(cl)Praktyczny schemat obliczeń równoległych
Oto kompletny, idiomatyczny przebieg pracy z obliczeniami równoległymi: wykryj liczbę rdzeni, utwórz klaster, wyeksportuj zależności, wykonaj obliczenia, zbierz wyniki i zawsze zatrzymaj klaster — nawet jeśli wystąpi błąd — używając on.exit().
library(parallel)
run_parallel <- function(data, fn, n_workers = detectCores() - 1) {
cl <- makeCluster(n_workers)
on.exit(stopCluster(cl)) # guaranteed cleanup
clusterExport(cl, 'fn', envir = environment())
result <- parLapply(cl, data, fn)
result
}
# Example: bootstrap mean estimation
samples <- lapply(1:100, function(i) rnorm(50, mean = 5, sd = 2))
means <- run_parallel(samples, mean)
cat('Grand mean:', round(mean(unlist(means)), 3), '\n')
cat('95% CI: [',
round(quantile(unlist(means), 0.025), 3), ',',
round(quantile(unlist(means), 0.975), 3), ']\n')Szybkie sprawdzenie
Jakiej funkcji należy użyć, aby zagwarantować wywołanie stopCluster(cl) nawet wtedy, gdy w kodzie równoległym wystąpi błąd?
Podsumowanie: pakiet parallel
Najważniejsze informacje:
detectCores()podaje liczbę dostępnych rdzeni; użyjdetectCores() - 1jako rozmiaru klastramakeCluster(n)/stopCluster(cl)zarządzają cyklem życia procesów roboczychclusterExport()kopiuje obiekty, aclusterEvalQ()uruchamia kod konfiguracyjny w procesach roboczychparLapply()/parSapply()to wieloplatformowe iteratory równoległemclapply()działa tylko w systemach Unix, ale szybciej się uruchamia dzięki forkowaniu- Używaj
on.exit(stopCluster(cl)), aby zagwarantować sprzątanie zasobów - Obliczenia równoległe opłacają się tylko w przypadku zadań wymagających dużej mocy obliczeniowej
# Minimal reproducible parallel pattern
library(parallel)
cl <- makeCluster(max(1, detectCores() - 1))
on.exit(stopCluster(cl))
clusterSetRNGStream(cl, iseed = 42)
result <- parSapply(cl, 1:8, function(x) x^2 + rnorm(1, 0, 0.1))
cat(round(result, 2), '\n')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 „Pakiet parallel i detectCores()” jest bezpłatna?
Tak — pełny tekst „Pakiet parallel i detectCores()” 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 „Pakiet parallel i detectCores()”?
Uruchamiaj klastry forkowane lub gniazdowe i rozdzielaj pracę między rdzenie procesora. Ć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 1 z 4.
Ile czasu zajmuje lekcja „Pakiet parallel i detectCores()”?
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
- Pakiet parallel i detectCores()
- Framework future
- furrr: równoległe operacje purrr
- Debugowanie i równoważenie obciążenia kodu równoległego