About concurrency and ensuring execution order with channels

First of all: Sorry if this topic is duplicated, but couldn’t find it :slight_smile:

Reading Crystal’s guide about Concurrency saw the following example, in the section “Spawning a fiber and waiting for it to complete”

channel = Channel(Nil).new

spawn do
  puts "Before send"
  channel.send(nil)
  puts "After send"
end

puts "Before receive"
channel.receive
puts "After receive"

The expected output in the example is:

Before receive
Before send
After receive

But my output, locally, with Crystal 0.35.1, is:

Before receive
Before send
After send
After receive

I’ve been told that the guide needs an update about how this should work. Also saw this Issue on GitHub about the topic.

The docs need to be updated or either say that the order of the result depends on the implementation and one shouldn’t rely on it. This is not a bug.

I’m missing the reasoning about this change, because I think that ensuring the execution order is crucial when working with Channels.

I would expect the example to work exactly as the guide. Whatever comes after receive should be executed always before the statements that come after send. The text “After send” shouldn’t even be printed.

Why this change? Am I missing something?

Thanks in advance.

EDIT: My opinion on this got an update, check reply below.

1 Like

After thinking again, and with the help of a good friend, I don’t think it’s bad for the channels behave this way. It’s actually more versatile.

If you need the waiting functionality I was requesting, it’s as simple as sending and receiving two times:

channel = Channel(Nil).new

spawn do
  puts "Before send"
  channel.send(nil)
  channel.send(nil)
  puts "After send"
end

puts "Before receive"
channel.receive
puts "After receive"
channel.receive
Before receive
Before send
After receive