The answer, for me, is always channels. What you put around the channels is the challenging part.
Channels are built to pass information between goroutines. If you are doing this via any other signaling, just don't. You can loop over channels for long running sequential reads, you can test them to see if they're ready to read or ready to write.
Honorable mention to context as well, extremely useful structure.