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: join channels #60829
Comments
see also #50324 |
I'm not entirely sure that what you want can be implemented in a reasonable way. You want to be able to block a goroutine until both a channel is ready to receive and at least one of a set of channels is ready to send. But in the general case other goroutines are sending and receiving on those channels. Today we can just put a goroutine to sleep until a channel is ready, then if we lock the channel, and it is still ready, we can proceed. To implement this scheme, we would need to check for the other side of the communication, and if that is not ready, we have to unlock the channel, and wait. But now that channel is ready, so shouldn't we just wake up again? So I guess we have to instead wait on the other channel(s), and hope that the first one is ready. It seems easy for a goroutine like that to starve. You said what you want, but you didn't say why you wanted it. When does an application need a synchronization mechanism more powerful than your version of |
In the past, I've wanted to connect an existing My motivation for this right now is to speed up and simplify a complex select loop with a mix of static and dynamic cases. Some benchmarks I wrote show about 2x overhead when using
I'm not very familiar with Go internals so please forgive my ignorance, but I think the join could be implemented purely in the channel send logic. There's no need for an intermediate goroutine that relays values from input to output. Spitballing:
Would something like that be workable? Some open issues:
|
Why is the exact buffering behavior that you describe important for this use case? It seems to me that you can't get that buffering behavior from Thanks for the implementation suggestion. What is supposed to happen if |
This proposal has been added to the active column of the proposals project |
Would making the channel sizes one less solve the problem? Would checking the length of the send channel before trying to receive a value work? |
Based on the discussion above, this proposal seems like a likely decline. |
No change in consensus, so declined. |
I would like to be able to connect (join, merge, pipe, mux, link) one or more input channels to a single output channel in a way that does not introduce unintentional buffering. For example, I would like to be able to write the following function:
It is possible to approximate the desired behavior using
reflect.Select
:However, the above does not satisfy the second bullet point:
This is because the local variable
v
acts like a channel buffer slot, effectively increasing the output channel's buffer size by one. This matters when send blocking is used for synchronization, as feedback for flow control (backpressure), for implicit acknowledgement, to limit concurrency, etc.I'm not sure what the solution should look like. Brainstorming some ideas:
append(outCh, inChs...)
It would also be nice to be able to transform an input value (perhaps to a different type) before it is sent to the output channel while preserving the "receive only happens if sent" behavior. I suspect that would open a can of worms, so it's probably best to leave that as a non-goal for this proposal. At least it would be good if the chosen solution for this proposal did not preclude such transformations as a future enhancement.
The text was updated successfully, but these errors were encountered: