-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Channel possibly not acting fair #111
Comments
This is a side effect of the fact that all the coroutines run under the same context in the same thread. Let me provide a step by step explanation of the first scenario (with unbuffered rendezvous channel):
The resulting "foo", "foo", "bar, "foo", "foo", "bar", etc does look counter-intivive, though. I'll keep this issue open for two reasons:
|
Thanks for the detailed walkthrough, output makes a lot more sense, also helped in figuring out how the delay(1L)'s were affecting it. |
Maybe |
One way to solve the issue of fairness and to make this behavior more intuitive is to change the logic (and specification) of |
The fair channels would also solve an issue of cancellability some people are facing with channels. The issue is that suspending invocations are cancellable only when they do suspend, so when you are continuously sending into the channel it is somewhat based on your luck (esp. in multi-thread scenarios) whether the sender can be cancelled. A send on a fair channel will always suspend (even if just to yield), so it will be always cancellable. This leads me think that we might want to have fair channels by default, while leaving an option of using non-fair channels as a performance optimization. |
Is it "safe" to support unfair channel? Maybe this decision should be motivated, if performance gain of unfair channel is negligible then I don't find any reason to supporting it. |
I'm going to find out the performance difference between fair/unfair channels before making this decision. It is also related to #113, since the performance difference should be more pronounced with SPSC channels. |
A little case study on Unlimited/Conflated Channel. Here an example code:
As explained above this program doesn't print anything, |
@elizarov since there were no posts here for quite some time: is there any updates on the before mentioned change in the behaviour? Is it planned to be implemented before experimental API and specification become stable? |
No update so far. We've been thinking about fairness of the channels, though, and here are some thoughts:
So, the current thinking that that we should make channels "partially fair" -- yield periodically (say on every 32 sends of something like that). It is not easy to add to the current design of channel, but as we work on a different channel implementation that feature can be quite easily incorporated at little additional cost. |
@elizarov are there any updates? Current suggestion to overcome this issue is to add |
|
@elizarov Thanks for your excellent explanation! For the documentation, I think we need a graphic GIF with multiple steps. Each step synchronize these graphs:
|
After the complete channels rewrite and six years down the road, we still have decided not to I think it's safe to close this one as "won't fix". |
Going to close this. I haven't written Kotlin in years and after an undergrad in CS and a few years working with distributed systems I don't think it's unreasonable the way these channels act. |
I noticed a few scenarios with channels where they do not seem to be fair and are filling their buffer in the wrong order. The main gist of the post can be seen from the first example, while the additional examples provide alternate scenarios with more unexpected outputs.
Outputs:
If the channel is given a buffer, the buffer is then filled with as many foo's as it can hold, and then a single BAR! which causes an output of the following when the channel has a buffer of 4:
The buffer is always filled to its max capacity with "foo" and only gets a "BAR!" afterwards at which point the send("BAR!") is suspended until the multiple foo's in the buffer are drained.
Filling the buffer like this also has some other weird results when a delay is added either before or after channel.receive() is called, as seen below:
Outputs:
Above is what I anticipated the original code to output since that seems more like the channel is acting fair.
Outputs:
From the code above and through some debugging, send("foo") is getting called, then it is getting to send("foo") a second time at which point it suspends, then it goes to send("BAR!") and suspends which causes the next strings in the buffer to be ordered such that "foo" is before "BAR!" for the first two items emitted.
And the last scenario:
Outputs:
This case was the weirdest as the execution of the while loop and the suspensions from send in sendString were in a very weird order that caused two "foo"'s to output in position 2 and 3.
Sorry for the long post, I noticed this while playing around with coroutines and did not think it was intended so I thought I would post here. If this is intended or there is a silly I'm making, any explanation is appreciated. Thanks.
The text was updated successfully, but these errors were encountered: