Concurrency and Parallelism in Ruby

Concurrency and Parallelism in Ruby

In programming, concurrency and parallelism are essential techniques for improving the performance and efficiency of code. Ruby, a popular programming language, offers various tools to handle these concept…


This content originally appeared on DEV Community and was authored by francesco agati

Concurrency and Parallelism in Ruby

In programming, concurrency and parallelism are essential techniques for improving the performance and efficiency of code. Ruby, a popular programming language, offers various tools to handle these concepts. Let's explore these techniques using a simple example.

Synchronous Code

Synchronous code executes tasks one after the other. Here's an example:

puts "Synchronous Code"
(1..5).each do |i|
  puts i
  sleep 1
end

In this code, numbers from 1 to 5 are printed with a 1-second delay between each number. The tasks run sequentially, meaning each number is printed only after the previous task (including the sleep) is completed.

Threads

Threads allow multiple sequences of instructions to run concurrently within the same program. Here's how we can use threads in Ruby:

puts "\nThreads"
threads = []
(1..5).each do |i|
  threads << Thread.new do
    puts i
    sleep 1
  end
end
threads.each(&:join)

In this example, each number from 1 to 5 is printed by a separate thread. All threads run concurrently, and the join method ensures that the main program waits for all threads to finish before proceeding. This makes the tasks run in parallel, potentially reducing the total execution time.

Fork

The fork method creates a new process, which is a separate instance of the Ruby interpreter:

puts "\nFork"
(1..5).each do |i|
  pid = fork do
    puts i
    sleep 1
  end
  Process.wait(pid)
end

In this code, fork creates a new process for each number. The parent process waits for each child process to complete using Process.wait. Each process runs independently, providing true parallelism on multi-core systems.

Fibers

Fibers are lightweight concurrency primitives that enable cooperative multitasking:

puts "\nFibers"
fibers = []
(1..5).each do |i|
  fibers << Fiber.new do
    puts i
    sleep 1
    Fiber.yield
  end
end
fibers.each(&:resume)

Each fiber runs a block of code and can be paused and resumed. This example prints numbers 1 to 5, pausing after each number. Although fibers provide concurrency, they do not run in parallel; the main program controls when each fiber resumes.

Ractor (Ruby 3)

Ractors, introduced in Ruby 3, enable true parallel execution by running code in isolated compartments:

puts "\nRactor"
ractors = (1..5).map do |i|
  Ractor.new(i) do |i|
    sleep 1
    puts i
  end
end
ractors.each(&:take)

In this example, each number from 1 to 5 is printed by a separate ractor. Ractors can run in parallel, making full use of multi-core processors. The take method waits for each ractor to finish and return its result.

When to Use Concurrency and Parallelism Techniques

Understanding when to use each concurrency and parallelism technique is crucial for optimizing performance in Ruby applications. Here's a guide:

Threads and Fibers

  • Threads: Use threads when you need to handle I/O-bound tasks, such as reading and writing files or making network requests. Threads can run concurrently but are limited by Ruby's Global Interpreter Lock (GIL), which means only one thread executes Ruby code at a time. Threads are heavier than fibers, requiring more resources, but they are suitable for tasks that involve waiting for external data.

  • Fibers: Fibers are even lighter than threads and are used for cooperative multitasking. A single thread can manage multiple fibers, making fibers ideal for managing multiple I/O-bound tasks without creating additional threads. Fibers need explicit control for yielding and resuming, which provides fine-grained control over task execution.

Fork and Ractor

  • Fork: Use fork for CPU-bound tasks that require significant computation and can benefit from true parallelism. Forking creates a new process, allowing it to run on a separate CPU core without being limited by the GIL. This is useful for heavy computations but incurs more overhead due to process creation and inter-process communication.

  • Ractor: Introduced in Ruby 3, ractors provide a way to achieve parallelism while ensuring thread safety. Ractors are ideal for heavy computations that can be distributed across multiple CPU cores. Unlike threads, ractors do not share memory and communicate via message passing, avoiding issues with the GIL and improving performance on multi-core systems.

Ruby provides multiple ways to handle concurrency and parallelism, each suited for different scenarios. Synchronous code is simple but sequential. Threads and fibers allow for concurrent execution within a single process, with threads offering parallelism on multi-core systems. Forking creates new processes for true parallelism, while ractors offer a modern and thread-safe way to achieve parallel execution in Ruby 3. Understanding these techniques helps developers write efficient and performant Ruby programs.


This content originally appeared on DEV Community and was authored by francesco agati


Print Share Comment Cite Upload Translate Updates
APA

francesco agati | Sciencx (2024-06-23T19:46:42+00:00) Concurrency and Parallelism in Ruby. Retrieved from https://www.scien.cx/2024/06/23/concurrency-and-parallelism-in-ruby/

MLA
" » Concurrency and Parallelism in Ruby." francesco agati | Sciencx - Sunday June 23, 2024, https://www.scien.cx/2024/06/23/concurrency-and-parallelism-in-ruby/
HARVARD
francesco agati | Sciencx Sunday June 23, 2024 » Concurrency and Parallelism in Ruby., viewed ,<https://www.scien.cx/2024/06/23/concurrency-and-parallelism-in-ruby/>
VANCOUVER
francesco agati | Sciencx - » Concurrency and Parallelism in Ruby. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/06/23/concurrency-and-parallelism-in-ruby/
CHICAGO
" » Concurrency and Parallelism in Ruby." francesco agati | Sciencx - Accessed . https://www.scien.cx/2024/06/23/concurrency-and-parallelism-in-ruby/
IEEE
" » Concurrency and Parallelism in Ruby." francesco agati | Sciencx [Online]. Available: https://www.scien.cx/2024/06/23/concurrency-and-parallelism-in-ruby/. [Accessed: ]
rf:citation
» Concurrency and Parallelism in Ruby | francesco agati | Sciencx | https://www.scien.cx/2024/06/23/concurrency-and-parallelism-in-ruby/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.