gab\channel
Channels are created with Channels.make:
ch := Channels.make
Send a value with <!:
ch <! 'hello'
Receive a value with >!:
value := ch >!
In gab, channels are unbuffered. Practically, this means that both operations are blocking: a send blocks until a receiver is ready, and a receive blocks until a sender is ready. For this reason, channels serve as both a primitive for sharing data, and way to synchronize fibers.
Note
For a comprehensive example of synchronizing fibers with channels, see the pub/sub broker example.
Buffered channels
While synchronization is useful, it can sometimes be a bottleneck for performance. If producers outpace consumers, then channels may become backed-up as producers have to block and wait for consumers.
In this scenario it is better to use a buffered channel, which can hold up to a certain number of values before producers have to begin blocking.
Lets build this with the primitives gab gives us!
buffered: .def (Channels, (n) :: do
input := Channels.make
output := Channels.make
Ranges.make(0 n).each () :: do
# Spawn n fibers to perform buffering.
Fibers.make () :: do
# Take out of input channel, and forward it to the output channel.
# Real code should handle the close gracefully, instead of unwrapping.
output <! (input >! .unwrap)
# Loop by calling self
self.()
end
end
(input, output)
end)
(input, output) := Channels.buffered(10)
The sender writes to input and can race N values ahead before blocking. The consumer reads from output. The N slot fibers sit between them, each capable of holding one value in flight.
Note
<! and >! are operator sends. The . prefix is optional but changes the precedence. Named sends (.name) bind tighter than bare operators.
ch <! value # operator form
ch.>! .println # dot prefix — binds tighter, result chains into .println