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

Task.Yield() is missing a .ConfigureAwait(bool) option #23498

Closed
AArnott opened this issue Sep 8, 2017 · 5 comments
Closed

Task.Yield() is missing a .ConfigureAwait(bool) option #23498

AArnott opened this issue Sep 8, 2017 · 5 comments
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Threading.Tasks
Milestone

Comments

@AArnott
Copy link
Contributor

AArnott commented Sep 8, 2017

As there are legitimate uses of Task.Yield() and legit uses of Task.ConfigureAwait(false), it's odd that there is no API to allow await Task.Yield().ConfigureAwait(false);. Anyone who must yield back to the caller but does not want to resume on the caller's SynchronizationContext has no convenient API to enable that.

In vs-threading we just filled this gap ourselves, but it seems like a worthwhile addition to .NET itself.

See also: https://stackoverflow.com/questions/28309185/task-yield-in-library-needs-configurewaitfalse

Proposal

public struct YieldAwaitable
{
   public ConfiguredYieldAwaitable ConfigureAwait(bool continueOnCapturedContext);
}

Or an equivalent extension method as we've defined in vs-threading.

@karelz
Copy link
Member

karelz commented Sep 10, 2017

@AArnott do you have a specific API in mind?

@kevingosse
Copy link
Contributor

kevingosse commented Sep 10, 2017

Semantically it feels a bit wrong to me. In my mind, Yield has the deeper meaning "resume where I left", which isn't entirely true anymore if you change the context. That said, I may be biased because of the existing method.
Your use case reminds me a lot of the old SwitchTo method that was removed from the TPL. Actually, vs-threading does implement SwitchTo (I used that code in some of my projects), I'm curious to know why you're trying to use await Task.Yield().ConfigureAwait(false) when you could use await TaskScheduler.Default.SwitchTo(true)?

@stephentoub
Copy link
Member

@AArnott
Copy link
Contributor Author

AArnott commented Sep 10, 2017

Your use case reminds me a lot of the old SwitchTo method that was removed from the TPL. Actually, vs-threading does implement SwitchTo (I used that code in some of my projects),

Yes, and that's exactly what we switched to using this week when we needed this.

I'm curious to know why you're trying to use await Task.Yield().ConfigureAwait(false) when you could use await TaskScheduler.Default.SwitchTo(true)?

Because it's where users expect to find it. Most users of await have never used or seen the SwitchTo method since it was only in the await previews. But they tend to be quite familiar with the concept of the .ConfigureAwait(false) appended syntax which does what they need when they don't want their caller to deadlock if blocking the UI thread on the result of this method.
In fact, although I wrote the SwitchTo method in the vs-threading library, when I realized during the recent PR linked to above that using await Task.Yield() would be problematic for the vs-streamjsonrpc library, I couldn't for the life of me think of an alternative. It was the PR author that eventually suggested this alternative API already exists.

In my mind, Yield has the deeper meaning "resume where I left", which isn't entirely true anymore if you change the context.

To me, I always think of the Yield() method as just forcing a yield. The "resume where I left" part of it that you mention is also true for awaiting any Task. So ya, the way await was designed was to pick up where you left off. But then in most cases you can configure it to resume on the threadpool, but there appears to be no way to yield and resume on the threadpool. await Task.Run is horribly inconvenient as @davidfowl mentions in #20025 because of forcing the rest of the method into a callback syntax, which isn't always possible or desirable.

I don't think most await users appreciate the difference between awaitable types like Task and YieldAwaitable. They just want to .ConfigureAwait(false) and they can't find it. And certainly for the users who don't use vs-threading, not even TaskScheduler.Default.SwitchTo(true) is a discoverable option for them.

So my argument is that since CoreFx doesn't offer a way to force a yield and resume off the caller's context, and we believe that requirement is a valid one, we should add the API to fill the gap in the place our existing users would expect to find it. And IMO that would be by configuring the awaitable they are already using.

do you have a specific API in mind?

Yes:

public struct YieldAwaitable
{
   public ConfiguredYieldAwaitable ConfigureAwait(bool continueOnCapturedContext);
}

Or an equivalent extension method as we've defined in vs-threading.

@stephentoub
Copy link
Member

stephentoub commented Sep 9, 2019

All good thoughts, but functionally it's a dup of https://github.com/dotnet/corefx/issues/15490. If we ever moved forward on enabling that functionality, either API could be considered. Thanks.

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 5.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 20, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Threading.Tasks
Projects
None yet
Development

No branches or pull requests

5 participants