channel = Channel(Int32).new
spawn do
puts "Before first send"
channel.send(1)
puts "Before second send"
channel.send(2)
end
puts "Before first receive"
value = channel.receive
puts value # => 1
puts "Before second receive"
value = channel.receive
puts value # => 2
The outpput in my machine is:
Before first receive
Before first send
Before second send
1
Before second receive
2
Which is different to
Output in the guide:
Before first receive
Before first send
1
Before second receive
Before second send
2
The output depends on what happens when you send a value over a channel. If there’s a fiber waiting for that value, I think some time ago that fiber was resumed and the fiber sending the value was paused. Eventually I think waj found out that either behavior was okay and sending the value but continuing in the current fiber is more performant, or I’m not sure, and that’s the current behavior.
I think the docs should be changed to say “an output similar to this one”, but not say “exactly this one”. Both behaviors are valid and they depend on implementation details.
Thanks,there are some changes in 0.31 that I found in the changelog, but I still don’t know how to make this two code work as expected, they work in 0.30.
Thanks, I am a frontend developer not familiar with concurrent, recently I am playing with crystal, write some nonsense code.
Here is what I thought, not sure If it is right.
Channel#receive consumes data. If a fiber got the value, other fibers won’t get it.
If the running time is on spawned fibers, it will run other fibers continually, but they won’t get the data since #1.
Channel#send would switch fibers only when that fibers have not been run, since #2, sometimes it may need to call Fibers.yield to let other fibers consume data.
Ok that may be a totally incorrect description about fibers, but I tried my best, the behavior seems like magic when more “send” and “receive” add to the code, it is hard for me to know who will recieve, then where the execution flows to or blocking at.
Hey @jacob, I suggest you think about it this way, to simplify things, until you familiarise yourself with communicating sequential processes a bit more.
Channel#send is a blocking operation, meaning that if no one is receiving on the other side, the running Fiber will suspend until a receiver shows up
Channel#receive is a blocking operation, too, meaning that the fiber will suspend until a fiber sends on the same channel.
I suggest you leave considerations around the order in which things run out of this, here is why:
in concurrent applications, the order in which fibers run might depend on the implementation - as @asterite mentioned
enabling the experimental Multi-Threading feature on the compiler will result in even more variability in the order in which fibers run/complete.
That said, the great news is, you don’t need to care about the order in which fibers run to write a correct concurrent application!
In absence of authoritative resources on Crystal’s concurrency, I suggest you have a look at what our neighbours go programmers preach. I’d recommend Concurrency in Go to get you started.