Select in Crystal

Our example demonstrates how to use select to wait on multiple channel operations. Combining fibers and channels with select is a powerful feature of Crystal.

require "time"

# For our example we'll select across two channels.
c1 = Channel(String).new
c2 = Channel(String).new

# Each channel will receive a value after some amount
# of time, to simulate e.g. blocking RPC operations
# executing in concurrent fibers.
spawn do
  sleep 1.second
  c1.send "one"
end

spawn do
  sleep 2.seconds
  c2.send "two"
end

# We'll use `select` to await both of these values
# simultaneously, printing each one as it arrives.
2.times do
  select
  when msg1 = c1.receive
    puts "received #{msg1}"
  when msg2 = c2.receive
    puts "received #{msg2}"
  end
end

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

$ time crystal run select.cr
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 Crystal version:

  1. We use Channel(String).new to create channels instead of make(chan string).
  2. Instead of goroutines, we use Crystal’s spawn to create new fibers.
  3. The select syntax in Crystal is very similar to the original, but we use when instead of case.
  4. We use sleep with a duration (e.g., 1.second) instead of time.Sleep.
  5. Channel operations use methods like send and receive instead of the <- operator.

The overall structure and functionality of the program remain the same, demonstrating how to use select to efficiently wait on multiple channel operations in Crystal.