-
Notifications
You must be signed in to change notification settings - Fork 531
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
Introduce right-biased race
variant
#3233
Conversation
Another idea: what if we just unbiased race itself? Rust does something interesting here in that it randomly flips whether it tests left or right first for completion. This has the effect of injecting fairness into the race. |
I'm not sure I understand. |
If both sides complete simultaneously, the left one will be chosen. :-) It's just hard to see this in practice. I'll try to put some more time into digesting this asap. |
So concretely I'm imagining something like this: IO.raceRightBiased(
IO.sleep(1.second),
IO.uncancelable(_ => IO.sleep(2.seconds).as(42))
) should complete as The real use-case is when the right fiber is a |
Erm, I just realized that the current naming is a bit unfortunate. So let's bikeshed that.
Based on #3232. I suggested this idea on Discord and Fabio said "interesting (edited)" so I knew I was onto something 😇
The basic idea is to introduce a variant of
race
that is robust to the case where the loser still completes (i.e. its outcome is notCanceled
), whether due to race condition or uncancelability. The idea is to right-bias the race, so that the "blessed" fiber is always reported as the winner unless it canceled.This sort of thing seems important when you are e.g. timing-out a
queue.take
orsemaphore.acquire
in which case if the action succeeds, you almost definitely want to know about it regardless of the timeout or not. In fact, I'd even argue that we should re-implement the timeout-based methods to be in terms of this method instead of vanillarace
.The motivating context is here:
https://github.com/typelevel/fs2/blob/dd20eb65b6cc59a923db44b21e29ec7c2e08e3a6/core/shared/src/main/scala/fs2/Stream.scala#L1442-L1460
Notice the comment about JS being "broken" which is what sent me on this rampage to begin with 😡
I had a difficult time reasoning about what exactly was going on there. Essentially a
semaphore.acquireN
is being timed-out. But to guard in case theacquireN
succeeded despite losing the race, it is followed by aguarantee
clause toreleaseN
. And then in the case that theacquireN
actually won the race, theacquireN
is actually done all over again since that was the intention all along. This all seems very convoluted to me.