
January 7, 2025
Concurrency and parallelism are key concepts in software development, enabling applications to handle multiple tasks efficiently. In Ruby, understanding and implementing these paradigms can significantly enhance the performance and responsiveness of your applications. Let’s dive into how Ruby handles concurrency and parallelism and explore practical examples to unlock the potential of your code.
Understanding Concurrency vs. Parallelism

Before we delve into Ruby-specific implementations, it’s essential to distinguish between concurrency and parallelism:
- Concurrency is about managing multiple tasks at once, switching between them to make progress.
- Parallelism involves executing multiple tasks simultaneously, typically across multiple CPU cores.
Ruby’s Global Interpreter Lock (GIL) in CRuby (MRI) restricts true parallelism for threads but allows concurrency. However, alternative Ruby interpreters like JRuby and TruffleRuby can achieve true parallelism.
Threads in Ruby
Threads are the building blocks for concurrency in Ruby. A thread is a lightweight process that can execute code independently.
Creating Threads
threads = []
5.times do |i|
threads << Thread.new do
puts "Thread #{i} is running"
sleep(1)
puts "Thread #{i} has finished"
end
end
threads.each(&:join)
In this example, five threads execute concurrently. The join method ensures the main program waits for all threads to complete.
Challenges with Threads
- Thread safety: Shared resources can lead to race conditions.
- Context switching: Threads incur overhead from switching between tasks.
Use synchronization tools like Mutex to manage shared resources:
mutex = Mutex.new
counter = 0
threads = []
10.times do
threads << Thread.new do
mutex.synchronize do
counter += 1
end
end
end
threads.each(&:join)
puts counter # Outputs 10
Fibers: Lightweight Concurrency
Fibers are more lightweight than threads and provide manual control over task switching. They are useful for cooperative multitasking.
Creating Fibers
fiber = Fiber.new do puts "Fiber starts" Fiber.yield puts "Fiber resumes" end fiber.resume puts "Back to main program" fiber.resume
Fibers do not run concurrently; they yield control explicitly. This makes them suitable for tasks like iterators or managing coroutines.
Use Case: Async I/O
Fibers are often used in libraries like async to manage I/O-bound operations efficiently:
require 'async'
Async do
task1 = Async { sleep(1); puts "Task 1 done" }
task2 = Async { sleep(2); puts "Task 2 done" }
[task1, task2].each(&:wait)
end
Parallelism with Processes
For true parallelism, Ruby processes can run on separate CPU cores. The Process module or libraries like Parallel enable this.
Using Processes
fork do puts "This is a child process" end puts "This is the main process"
The fork method creates a new process, but it’s available only on Unix-based systems. Use Process.wait to wait for child processes.
The Parallel Gem
require 'parallel' results = Parallel.map([1, 2, 3, 4], in_processes: 2) do |num| num * 2 end puts results # [2, 4, 6, 8]
Choosing the Right Tool
- Use Threads for concurrent tasks where GIL constraints are acceptable.
- Use Fibers for cooperative multitasking, especially for I/O-bound tasks.
- Use Processes for CPU-intensive tasks requiring true parallelism.
Beyond Threads and Fibers: Exploring JRuby and TruffleRuby
Alternative Ruby implementations like JRuby and TruffleRuby bypass the GIL, allowing true parallel threads. This makes them ideal for performance-critical applications.
Example: Parallel Threads in JRuby
threads = []
10.times do |i|
threads << Thread.new do
puts "Thread #{i} is running"
end
end
threads.each(&:join)
In JRuby, threads execute in parallel, leveraging multi-core processors.
Conclusion
Concurrency and parallelism are powerful tools for building efficient Ruby applications. By leveraging threads, fibers, and processes, you can optimize your code for various workloads. Consider the requirements of your application and choose the right approach to harness Ruby’s concurrency features effectively.

Ready to dive deeper? Share your thoughts or questions below – let’s keep the conversation going!

Do you need more hands for your Ruby on Rails project?
