Select in Ruby

Our example demonstrates how to wait on multiple channel operations using Ruby’s Thread and Queue classes. This combination provides a powerful feature for concurrent programming in Ruby.

require 'thread'

def main
  # For our example we'll select across two queues.
  q1 = Queue.new
  q2 = Queue.new

  # Each queue will receive a value after some amount
  # of time, to simulate e.g. blocking RPC operations
  # executing in concurrent threads.
  Thread.new do
    sleep(1)
    q1.push("one")
  end

  Thread.new do
    sleep(2)
    q2.push("two")
  end

  # We'll use a loop to await both of these values
  # simultaneously, printing each one as it arrives.
  2.times do
    Thread.new do
      result = Queue.new
      Thread.new { result.push([:q1, q1.pop]) }
      Thread.new { result.push([:q2, q2.pop]) }
      queue, msg = result.pop
      puts "received #{msg}"
    end.join
  end
end

main

We receive the values "one" and then "two" as expected.

$ time ruby select.rb
received one
received two

Note that the total execution time is only ~2 seconds since both the 1 and 2 second sleep operations execute concurrently.

real    0m2.245s

In this Ruby implementation, we use Thread to create concurrent operations and Queue to simulate channels. The select functionality is mimicked by creating separate threads for each queue and using another queue (result) to collect the first available message. This approach allows us to wait on multiple operations simultaneously, similar to Go’s select.