Non Blocking Channel Operations in Crystal
Our program demonstrates non-blocking channel operations using select
with a default
clause. This allows us to implement non-blocking sends, receives, and multi-way selects.
require "channel"
messages = Channel(String).new
signals = Channel(Bool).new
# Here's a non-blocking receive. If a value is
# available on `messages` then `select` will take
# the `messages.receive` case with that value. If not
# it will immediately take the `default` case.
select
when msg = messages.receive
puts "received message #{msg}"
else
puts "no message received"
end
# A non-blocking send works similarly. Here `msg`
# cannot be sent to the `messages` channel, because
# the channel has no buffer and there is no receiver.
# Therefore the `else` case is selected.
msg = "hi"
select
when messages.send(msg)
puts "sent message #{msg}"
else
puts "no message sent"
end
# We can use multiple `when` clauses above the `else`
# clause to implement a multi-way non-blocking
# select. Here we attempt non-blocking receives
# on both `messages` and `signals`.
select
when msg = messages.receive
puts "received message #{msg}"
when sig = signals.receive
puts "received signal #{sig}"
else
puts "no activity"
end
To run the program:
$ crystal run non_blocking_channel_operations.cr
no message received
no message sent
no activity
In Crystal, we use Channel
to create channels. The select
statement is used for non-blocking operations on channels. Instead of case
, we use when
for each channel operation, and else
instead of default
for the fallback case.
Note that Crystal’s channels are unbuffered by default, similar to Go. If you need buffered channels, you can create them with Channel(T).new(capacity)
.
Crystal’s concurrency model is based on fibers, which are lightweight threads managed by the Crystal runtime. This is similar to Go’s goroutines, allowing for efficient concurrent programming.