3 ms·
> In Go, we can do this by closing a channel, because a receive operation on a closed channel can always proceed immediately, yielding the element type's zero v
by songgao 13y ago
> In Go, we can do this by closing a channel, because a receive operation on a closed channel can always proceed immediately, yielding the element type's zero value.
for n := range c {
select {
case out <- n:
case <-done:
}
}
This, is brilliant.
- jbert 13y agoI wasn't quite getting that code when I first read it. Now I can see it allows you do "discard" all the pending reads from the input channel (and avoid writing to a possibly-closed 'out' channel), but wouldn't it be better to break the loop in this case for an immediate exit? i.e. go for 'interrupt' semantics, rather than 'drain'?
- Zariel 13y agoI think its so that the channel is empty, and will have no references so it will be garbage collected.
- Sajmani 13y agoYes, interrupt is better, and the article explains how to do that a few paragraphs later: for n := range in { select { case out <- n * n: case <-done: return } } If you allow pipeline stages to interrupt their receive loop instead of draining the inbound channel, then _all_ send operations need to be governed by done. Otherwise the interrupted receive loop may block the upstream sender.
- songgao 13y agoThe loop (particularly `range c`) keeps getting element out of `c` and assigning it to `n`. If it's "done", then `n` wouldn't be sent into `out`, but still gets read from the channel `c` constantly. In other words, it's the loop itself that makes sure everything sent into channel `c` is consumed. If `break` is used, for loop is terminated once it's "done", hence nothing would be reading from channel `c`. The previous station in the pipeline would then block at sending operation.