Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: better channel semantics #31152

Closed
mcandre opened this issue Mar 29, 2019 · 2 comments
Closed

proposal: better channel semantics #31152

mcandre opened this issue Mar 29, 2019 · 2 comments
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change
Milestone

Comments

@mcandre
Copy link

mcandre commented Mar 29, 2019

Goroutines and Go channels are phenomenally powerful, and even relatively easy to use for simple programs. The fact that some limited deadlock detection is built-in is a tremendous win for concurrent applications! However, I think there are ways to improve channel semantics for some really common use cases, and I'd like to know what people think about what the channel API could look like for Go v2.0.

First, I observe that channels can act like iterators in Go, providing a relatively convenient syntax for achieving stream-like data and computation flows. The thing is, I often want to insert an element into a channel without actually getting blocked for a recipient to read it. So I end up doing a lot of go func() { ... }() wrapping around channel sends just to present the overall program in a somewhat linear fashion. I would like a syntax for sending messages to channels that does not block, as opposed to the <- operator.

I know that I can declare a buffer size for my channels, but that's not particularly helpful for resolving the problem of asynchronous sending. In some cases, I won't know ahead of time exactly how many messages I need to send. A function can pass me a writable channel, where I don't have the option to declare a buffer size. Finally, it is also common for the receiver of the channel to die, garbage collect its end of the channel, or otherwise be in a state where it is not consuming messages / unblocking my program counter. As I build longer and deeper channel combinations, the probability of a deadlock due to over- or underaggressive reaction to error or done states, rises to the level of inescapable deadlock, somewhere lost in the woods.

Perhaps the biggest problem that I'm encountering with Go channels, is nested back propagation, where I need to dedicate specific channels for signaling an early termination error / done signal. Just one level deep can lead to unit tests stalling, because some done signal wasn't sent, or worse, was sent to a goroutine that had already left the party. Could there be a way to detect when a channel has closed, so that the listener no longer tries to send/receive messages on it?

Furthermore, what to do when you are trying to send a done signal, and then the done recipient dies? Would be nice for Go to provide some sort of indication that the message wasn't sent. Though of course we shouldn't use error channels to relay this information, as that just moves the problem! Hmm, maybe I need to stop writing so many asynchronous functions and just write blocking functions with an error return signature :P

Not to mention that a channel for signaling done is a common need, with few good conventions. chan bool begs the question, what would receiving false even mean? And chan struct{} is quite ugly. At the very least, we could get some decent aliases in the stdlib: type Done = struct{}, type DoneMessage = struct{}{}. If not the aforementioned method for querying when a channel has closed, which would be best of all!

Done channels, data channels, and error channels are reasonably good to bundle into a reusable structure, instead of having to pass these around individually. Though of course this would only be practical for the stdlib were Generics introduced. Hmm, maybe a convention of using chan (error, bool, <your-type-here>) for error, done status, successful result?

Just some thoughts as I get my head around some gnarly concurrent apps.

@networkimprov
Copy link

Related:
#20868 - proposal: channel buffer pools
#20352 - proposal: add support for unlimited capacity channels
#26282 - proposal: clone and splice, new channel primitives

@bradfitz bradfitz added the LanguageChange Suggested changes to the Go language label Mar 30, 2019
@andybons andybons changed the title Better channel semantics all: better channel semantics Apr 3, 2019
@andybons andybons changed the title all: better channel semantics proposal: better channel semantics Apr 3, 2019
@gopherbot gopherbot added this to the Proposal milestone Apr 3, 2019
@andybons andybons added v2 An incompatible library change and removed Proposal labels Apr 3, 2019
@ianlancetaylor
Copy link
Contributor

This would be better discussed on a forum like golang-nuts; see https://golang.org/wiki/Questions . I think it would be best to develop some more specific suggestion in a forum, and then open an issue with those. At the moment there is no action we can take with this issue because there is no concrete proposal. Thanks.

@golang golang locked and limited conversation to collaborators May 6, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change
Projects
None yet
Development

No branches or pull requests

6 participants