SIZE = ARGV[0].to_i
def generate(chan)
i = 2
loop do
chan.send(i)
i += 1
end
end
I understand this. Takes a channel and just writes increasing numbers to it.
def filter(in_chan, out_chan, prime)
loop do
i = in_chan.receive
if i % prime != 0
out_chan.send(i)
end
end
end
I also understand this. Read from one channel and sends what it read out another channel when its divisible by “prime”.
ch = Channel(Int32).new
spawn generate(ch)
Start fiber (or thread) with generator. Got that.
SIZE.times do
prime = ch.receive
puts prime
ch1 = Channel(Int32).new
spawn filter(ch, ch1, prime)
ch = ch1
end
Now here I’m completely lost.
SIZE is the number of primes to compute. So, this spawns, let’s say, 15 fibers, who all read on the channel “ch” which is either the generated number or the output of the filter function?
Why is this not random? if we have multithreading, why do things still happen in a defined order?
The Filter function does this in a loop without end condition. Why does this even work, i.e. ever end?
If I understand correctly (both your code and the implementation of Channel), channels provide some level of order in concurrent code. For example, in 3 different fibers all call receive on the same channel, they will get values in the order in which they called receive.
So sending to a channel, receiving from a channel, and the values in the channel are all separate FIFO queues. The first sending fiber will succeed in sending the first value to the first receiving fiber every single time.
It looks like once you’ve received SIZE elements out of the channel in generate, the main fiber completes. When the main fiber completes, the entire program exits. For example, the following code will exit despite work still being done in another fiber:
spawn { loop {} }
If all of your application’s work is being done in other fibers, you may need to put the main fiber to sleep indefinitely:
spawn { loop {} }
sleep # Let the other fiber do its work
This happens in multithreaded code, too. If the main thread is done, the entire program exits. This is different from Node.js, for example, where if any setTimeout callbacks are still enqueued, the app will continue until there are none left to execute.
I think you are missing that ch changes on each iteration on the loop (ch = ch1). So the main program will wait to receive the first number that survives the filtering.