For example, let's say I have []foo as input and I'm going to call a service on every element of the slice.
You could do it with channels, but oftentimes I'll reach for creating a slice of results and passing each goroutine an index into the slice. That way I can avoid any overhead that comes from having what is effectively a queue with a lock.
It depends on what I'm doing, how I want to treat failures of a single goroutine, etc. of course.
I default to never returning channels unless it's a requirement for the use case (e.g. context.Done() returns a channel so callers can listen for when the context is closed).
Callers can always create goroutines to make your code run concurrently. It's more annoying to erase channels when they aren't useful to the caller (e.g. if you made all functions that make HTTP calls return a channel because you assume callers want a new goroutine, but I already have my own goroutine per request)
Beyond that, some specific examples would be helpful so I can tailor my advice
For example, let's say I have []foo as input and I'm going to call a service on every element of the slice.
You could do it with channels, but oftentimes I'll reach for creating a slice of results and passing each goroutine an index into the slice. That way I can avoid any overhead that comes from having what is effectively a queue with a lock.
It depends on what I'm doing, how I want to treat failures of a single goroutine, etc. of course.
I default to never returning channels unless it's a requirement for the use case (e.g. context.Done() returns a channel so callers can listen for when the context is closed).
Callers can always create goroutines to make your code run concurrently. It's more annoying to erase channels when they aren't useful to the caller (e.g. if you made all functions that make HTTP calls return a channel because you assume callers want a new goroutine, but I already have my own goroutine per request)
Beyond that, some specific examples would be helpful so I can tailor my advice