go

Visitor pattern vs channel in Go


If there is a list that needs to be generated and processed (ideally, while being generated), what is the convention? It seems like callbacks aren't used as much whereas channels are the universal favorite. There won't be a decisive benefit to either providing a callback to be invoked for each item versus launching a goroutine to generate the list and synchronously reading and processing each item.

I'd understand if there were more than one task to be done while waiting for the list to finish or both were performing expensive tasks and one might be able to work on the last item while the next item is being produced, but that isn't the case, here. Both the producer and consumer are low-cost.

Note that this question is comparing goroutines versus callbacks versus other questions that compare channels versus closures. They're not exactly the same question and may not turn up in the same search, and there is value in knowing that both questions have been asked even if they have the same ultimate answer.


Solution

  • The convention is to use callbacks. Here are a couple of examples in the standard library: filepath.Walk, ast.Walk.

    A drawback of the channel with generator goroutine pattern is that it leaks a goroutine when the consumer does not receive until the channel is closed. Another issue is that creates an opportunity for data races. The standard library used this pattern in the early days of Go. This code was removed before Go 1 because of these issues.