Parallel Computing in R Exercises: 15 Practice Problems

Fifteen practice problems on parallel computing in R: mclapply, future, furrr, doParallel, parallel maps. Hidden solutions.

library(future)
library(furrr)
library(parallel)
library(foreach)
library(future.apply)
library(tibble)

Exercise 1: detectCores

Difficulty: Beginner.

Show solution
parallel::detectCores()

Exercise 2: mclapply (unix)

Difficulty: Intermediate.

Show solution
parallel::mclapply(1:4, function(x) { Sys.sleep(0.5); x^2 }, mc.cores = 2)

Exercise 3: parLapply with cluster

Difficulty: Advanced.

Show solution
cl <- parallel::makeCluster(2)
parallel::parLapply(cl, 1:4, function(x) x^2)
parallel::stopCluster(cl)

Exercise 4: future multisession

Difficulty: Intermediate.

Show solution
future::plan(future::multisession, workers = 2)
f <- future::future({ Sys.sleep(0.5); 42 })
future::value(f)

Exercise 5: furrr future_map

Difficulty: Intermediate.

Show solution
future::plan(future::multisession, workers = 2)
furrr::future_map_dbl(1:4, ~ { Sys.sleep(0.5); .x^2 })

Exercise 6: future_map_dfr

Difficulty: Intermediate.

Show solution
future::plan(future::multisession, workers = 2)
furrr::future_map_dfr(1:3, ~ tibble::tibble(n = .x, sq = .x^2))

Exercise 7: Globals: pass variables

Difficulty: Advanced.

Show solution
future::plan(future::multisession, workers = 2)
k <- 10
furrr::future_map_dbl(1:5, ~ .x * k)

Exercise 8: Set seed reproducibly

Difficulty: Advanced.

Show solution
future::plan(future::multisession, workers = 2)
furrr::future_map_dbl(1:5, ~ runif(1), .options = furrr::furrr_options(seed = 123))

Exercise 9: doParallel + foreach

Difficulty: Advanced.

Show solution
cl <- parallel::makeCluster(2)
doParallel::registerDoParallel(cl)
foreach::foreach(i = 1:4, .combine = c) %dopar% { Sys.sleep(0.3); i^2 }
parallel::stopCluster(cl)

Exercise 10: future plan sequential

Difficulty: Beginner. Reset to sequential.

Show solution
future::plan(future::sequential)

Exercise 11: Compare serial vs parallel

Difficulty: Advanced.

Show solution
slow <- function(x) { Sys.sleep(0.5); x^2 }
future::plan(future::multisession, workers = 4)
serial_time <- system.time(lapply(1:8, slow))
parallel_time <- system.time(furrr::future_map(1:8, slow))
list(serial = serial_time["elapsed"], parallel = parallel_time["elapsed"])

Exercise 12: parSapply

Difficulty: Intermediate.

Show solution
cl <- parallel::makeCluster(2)
parallel::parSapply(cl, 1:5, function(x) x^2)
parallel::stopCluster(cl)

Exercise 13: Caret parallel via doParallel

Difficulty: Advanced.

Show solution
cl <- parallel::makeCluster(2)
doParallel::registerDoParallel(cl)
# train() with method="rf" auto-parallelizes when registered
parallel::stopCluster(cl)

Exercise 14: future apply

Difficulty: Intermediate.

Show solution
future::plan(future::multisession, workers = 2)
future.apply::future_sapply(1:5, function(x) x^2)

Exercise 15: Stop cluster cleanly

Difficulty: Beginner.

Show solution
cl <- parallel::makeCluster(2)
# ... do work ...
parallel::stopCluster(cl)

What to do next

  • R-Performance-Optimization-Exercises (shipped), single-thread first.
  • purrr-Exercises (shipped), serial map functions before parallel.