R
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Data Structures
-
Section 4: Data Manipulation
-
Section 5: Visualization and Statistics
-
Section 6: Advanced R
-
Section 7: Practical Projects
-
Section 8: Interview Practice
-
Section 9: More Practice Exercises
-
Section 10: Shiny Apps in Depth
-
Section 11: More Data Wrangling
-
Section 12: Tidyverse Deep Dive
-
Section 13: Statistical Modeling Deep Dive
-
Section 14: Machine Learning in R
-
Section 15: R Visualization Deep Dive
-
Section 16: R Package Development Deep Dive
-
Section 17: R for Reproducible Research
-
Section 18: R and Databases
-
Section 19: R Performance Optimization
-
Section 20: Bioinformatics and Specialized R
-
Section 21: More Shiny Practice
-
Section 22: More Practice Exercises
-
Section 23: R Data Structures Deep Dive
-
Section 24: More Interview and Review
-
Section 25: R for Business Analytics
-
Section 26: R Text Mining and NLP
-
Section 27: R Spatial Data Analysis
-
Section 28: R Deep Learning
-
Section 29: Advanced Statistical Techniques
-
Section 30: R Object Systems Deep Dive
-
Section 31: R Environments and Metaprogramming
-
Section 32: R for Finance
-
Section 33: R for Clinical and Health Data
-
Section 34: More Shiny Advanced Practice
-
Section 35: R Data Cleaning Deep Dive
-
Section 36: R Reporting Automation
-
Section 37: More Practical Projects Round 2
-
Section 38: R Ecosystem and Career
-
Section 39: More Visualization Practice
-
Section 40: R for Experimentation
-
Section 41: R for Genomics and Bioinformatics Deep Dive
-
Section 42: R for Marketing Analytics
-
Section 43: R Data Import/Export Deep Dive
-
Section 44: R String Processing Deep Dive
-
Section 45: R for Actuarial and Insurance Analytics
-
Section 46: R Testing and Quality Assurance Deep Dive
-
Section 47: R Version Control and Collaboration
-
Section 48: R Advanced Functional Programming
-
Section 49: R for Supply Chain and Operations
-
Section 50: More Practice Exercises Round 3
-
Section 51: R Dashboards and BI Integration
-
Section 52: R Data Governance and Ethics
-
Section 53: More Modeling Practice
-
Section 54: R Final Capstone Projects
-
Section 55: R for Sports Analytics
-
Section 56: More Interview Practice Round 2
-
Section 57: R Networking and APIs
-
Section 58: R for Environmental Science
-
Section 59: R Notebook and Documentation Practices
-
Section 60: More Data Wrangling Mastery
-
Section 61: R for A/B Testing at Scale
-
Section 62: R Package Ecosystem Deep Dive
83: Parallel Processing with the parallel Package
Up until now, every line of code you've written in R has been running on a single CPU core. For most scripts, that's plenty. But once you start dealing with massive simulations or iterating over thousands of heavy computations, you'll notice R just sitting there, chewing through one task at a time while the other seven or fifteen cores on your machine are basically idling. It feels like a waste.
The parallel package is the standard way to wake those other cores up. Today, we're going to use it to estimate the value of Pi using a Monte Carlo simulation. It's a computationally "expensive" way to find Pi—essentially throwing random darts at a square and seeing how many land in a circle—which makes it the perfect candidate for parallelization.
The bottleneck: Estimating Pi with a shotgun approach
First, let's write a simple function that performs one "batch" of these random throws. We'll generate random X and Y coordinates between 0 and 1, and check if they fall within the unit circle.
estimate_pi <- function(n) {
x <- runif(n)
y <- runif(n)
# A point is inside the circle if x^2 + y^2 <= 1
inside <- sum(x^2 + y^2 <= 1)
return(inside / n * 4)
}
If I want to run this simulation 100 times with 1 million points each to get a stable average, doing it sequentially with lapply is slow. I can feel the lag. Instead, I want to split those 100 iterations across all my available cores.
Spinning up the worker cluster
To do this, we need to create a "cluster." Think of this as launching several invisible, separate instances of R in the background that just wait for instructions from your main session.
library(parallel)
# Detect how many cores I have
num_cores <- detectCores()
# I'll leave one core free so my computer doesn't freeze up completely
cl <- makeCluster(num_cores - 1)
Now that the cluster is live, I'll use parLapply. It's almost identical to lapply, but the "par" stands for parallel. It tells R to ship the work off to those background instances we just created.
Wait, where did my function go?
Here is where I almost always trip up the first time I use this package. I'll try to run the simulation like this:
# This is where I usually make my mistake
iterations <- 1:100
results <- parLapply(cl, iterations, function(i) estimate_pi(1e6))
If you ran that, you'd get an error saying could not find function "estimate_pi". It's frustrating because the function is right there in your environment! But remember: those worker nodes are separate R processes. They don't share your global environment. They are blank slates. They have no idea what estimate_pi is because I never told them about it.
Shipping the logic to the workers
To fix this, we have to explicitly "export" the function (and any other variables the function depends on) to every node in the cluster using clusterExport. This is the missing link.
# Export the function to the worker nodes clusterExport(cl, "estimate_pi") # Now we run it again results <- parLapply(cl, iterations, function(i) estimate_pi(1e6)) # Calculate the final average of our simulations final_pi <- mean(unlist(results)) print(final_pi)The speed difference is immediate. Instead of one core doing 100% of the work, the load is distributed. If you have 8 cores, you're theoretically cutting your wait time down significantly.
Tearing down the cluster
One thing you cannot forget: those worker nodes don't just vanish when your script ends. They stay alive in your system memory. If you keep creating clusters without closing them, you'll eventually run out of RAM and your OS will start screaming.
stopCluster(cl)Always pair your
makeClusterwith astopCluster. I usually put the stop command in afinallyblock or immediately after the parallel call to make sure I don't leave "ghost" R sessions haunting my machine.
📋 Practical Task
Parallelizing Dice-Roll Simulations
You need to determine the theoretical average of a 6-sided die roll (which is 3.5) using a simulation. Instead of one giant simulation, you will run 500 separate simulations, each rolling the die 10,000 times.
Write a script that does the following:
- Defines a function
roll_dicethat takes an integern, simulatesnrolls of a 6-sided die usingsample(), and returns themean()of those rolls. - Creates a cluster using
makeCluster()based on the number of available cores. - Uses
clusterExport()to ensure the worker nodes can see theroll_dicefunction. - Uses
parLapply()to run the simulation 500 times (with 10,000 rolls per simulation). - Calculates the overall mean of all the simulation results.
- Shuts down the cluster using
stopCluster().
There are no comments for now.