1. Technology
You can opt-out at any time. Please refer to our privacy policy for contact information.

Threads

By

Threads are the primary method of parallelism in Ruby. While there is normally one path of execution through your program, a program that has threads may have multiple paths of execution concurrently.

However, Ruby's parallelism in MRI (the default and most widely used Ruby interpreter) only allows for one thread to be active at any given time. This sounds counterintuitive, why have threads if there is no concurrency? While only one thread may be executing at any given time, any number of threads can be waiting for IO operations, so IO-bound programs (programs that run slowly because they're waiting for IO operations to finish) can be sped up, allowing the IO operations to be run in parallel. CPU-bound programs (programs that run slowly because the CPU needs time to crunch numbers) cannot be sped up in MRI using threads. On the other hand, JRuby has full threading. Both CPU-bound and IO-bound programs can be parallelized and sped up using threads.

Using Threads

The threading interface in Ruby is very simple. So simple, here is a quick example program that shows you how threads are almost always used.


#!/usr/bin/env ruby
require 'thread'

threads = []
10.times do
  # Make sure the threads are IO bound
  threads << Thread.new do
    duration = rand(10)
    puts "Sleeping for #{duration} seconds"
    sleep duration
  end
end

threads.each{|t| t.join }

Firstly, require thread. This gives you access to the Thread class. Next, create new threads with Thread.new. The thread constructor takes a block, which will start execution immediately in a new thread, while the main thread (or the thread that created the new thread, since threads and create other threads) also immediately continues onward.

Note that all the threads are kept track of in the threads variable. This is convention, you can keep track of them any way that suits you, or not keep track of them at all (more on that later), but you'll need a list of the threads if you wish to join them. "Joining" a thread is to wait for the thread to finish executing (in this case, when it reaches the end of the block you passed to the thread constructor) and terminate it, cleaning up its memory and killing off the OS process used to schedule the thread. At the end of this program, it joins all the threads it created, which in turn waits for each thread to finish sleeping before continuing.

So, pop quiz. Each thread waits for a random amount of seconds (up to 10 seconds). How long does the program take to execute? If you had done this sequentially, it would have taken anywhere from 10 to 100 seconds. However, since the threads spend all of their time waiting for the sleep method to finish (which relinquishes control of the thread to the OS, asking the OS to wake it up later) they can all run in parallel. So this program will take as long as the longest sleep time (up to 10 seconds). This example is a bit silly, but replace those sleep calls with HTTP downloads of large files and now you have something useful.

To read more about threads, see the next article in this series: Thread Pools.

  1. About.com
  2. Technology
  3. Ruby
  4. Advanced Ruby
  5. Threads

©2014 About.com. All rights reserved.