0

So Task.Yield will yield execution back to the caller immediately, essentially making whatever is bellow it in a continuation of the task returned by it (Task.Yield).

Assuming an Asp.Net Core application which does not have a SynchronizationContext, is there any functional difference from awaiting Task.Yield and passing that continuation to Task.Run?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
underthevoid
  • 513
  • 1
  • 6
  • 17
  • I am assuming that your question has educational purposes. For practical purposes, if your intention is to switch to the `ThreadPool` imperatively, a dedicated mechanism like noseratio's [`SwitchTo`](https://stackoverflow.com/questions/15363413/why-was-switchto-removed-from-async-ctp-release "Why was “SwitchTo” removed from Async CTP / Release?") will communicate this intention clearly, and enforce this behavior robustly, instead of relying on a mechanism like `Task.Yield` that may produce this behavior accidentally, depending on the ambient state of the application. – Theodor Zoulias Aug 21 '21 at 15:58
  • @TheodorZoulias yes, your assumption is right. – underthevoid Aug 21 '21 at 15:59
  • 2
    The code is already running in a thread pool thread. Why would you want to force context switching and the usage of more threads? – Paulo Morgado Aug 21 '21 at 17:26
  • @PauloMorgado can you elaborate what you said? That doesn't make sense to me. What code is already running in a threadpool thread? – underthevoid Aug 21 '21 at 21:17

2 Answers2

4

Assuming an Asp.Net Core application which does not have a SynchronizationContext, is there any functional difference from awaiting Task.Yield and passing that continuation to Task.Run?

There's practically no difference. await Task.Yield will queue the continuation to the thread pool and return to the caller. await Task.Run will queue its delegate to the thread pool and return to the caller.

Personally, I prefer Task.Run because it has a very explicit intent and because it's unambiguous (i.e., in other scenarios such as GUI threads, await Task.Yield will not queue to the thread pool, while await Task.Run always does the same thing regardless of context).

As others have noted in the comments, there's no reason to actually do either one on ASP.NET Core, which is already running on thread pool threads and does not have a request context. It would add a little overhead to the request while providing no benefit at all.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Actually I was with the `BackgroundService` in mind when asking this question (you answered me in another question about that too :P). `BackgroundService.ExecuteAsync` will actually block the application-starting thread before it yields back to the caller, by awaiting `Task.Yield` for instance. If I understood correctly what you said, `Task.Run` should be preferred in that case of `BackgroundService.ExecuteAsync` because of what it express. While `Task.Yield` will do the same (as you said), it express less intent than `Task.Run`, and so the later should be used. – underthevoid Aug 21 '21 at 19:49
  • For those interested in that another topic I referred to: https://stackoverflow.com/questions/68825893/why-a-blocking-call-inside-backgroundservice-executeasync-is-not-blocking-the-ma/68833570#68833570 – underthevoid Aug 21 '21 at 19:51
  • 1
    @underthevoid: Ah. Yes, [I recommend using `Task.Run` in that scenario](https://blog.stephencleary.com/2020/05/backgroundservice-gotcha-startup.html). – Stephen Cleary Aug 21 '21 at 20:37
-4

They're difference, if you take the result as educational view point. Better explaination can be found here, here and... if you want to see how it compile to IL, take a shot here.

From real world project, as i saw the only purpose and benefit from Task.Yield is to force a task to run asynchronous. (decorate a method as async/await doesn't ensure that they will run asynchronously, especially with the new ValueTask).

So, forcing immediate return the execution to the caller, means that you doesn't care it's final result (for example: you call an API, but never care about the response).

Which according to me, in the asp.net core server side process, have a better approach, that's build a FireAndForget service and pass the task to it, let they run on a separate scope would be much safer.

That's cause the Task.Yield will capture the current context and goes on with it. So an exception would very likely to happen if you use resource that related to the current execution scope, HttpRequest is a particular case, which normally finish in less than a second(HttpContext already got disposed).

Gordon Khanh Ng.
  • 1,352
  • 5
  • 12