Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"await Task.Yield()" and its alternatives

Tags:

If I need to postpone code execution until after a future iteration of the UI thread message loop, I could do so something like this:

await Task.Factory.StartNew(     () => {         MessageBox.Show("Hello!");     },     CancellationToken.None,     TaskCreationOptions.None,     TaskScheduler.FromCurrentSynchronizationContext()); 

This would be similar to await Task.Yield(); MessageBox.Show("Hello!");, besides I'd have an option to cancel the task if I wanted to.

In case with the default synchronization context, I could similarly use await Task.Run to continue on a pool thread.

In fact, I like Task.Factory.StartNew and Task.Run more than Task.Yield, because they both explicitly define the scope for the continuation code.

So, in what situations await Task.Yield() is actually useful?

like image 309
noseratio Avatar asked Dec 02 '13 02:12

noseratio


People also ask

What does await task Yield do?

You can use await Task. Yield(); in an asynchronous method to force the method to complete asynchronously. If there is a current synchronization context (SynchronizationContext object), this will post the remainder of the method's execution back to that context.

What happens if you dont await task?

If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.

Do I need await Task run?

If you use Task. Run with an I/O operation, you're creating a thread (and probably occupying a CPU core) that will mostly be waiting. It may be a quick and easy way to keep your application responsive, but it's not the most efficient use of system resources. A much better approach is to use await without Task.

What is the difference between task and async?

Async methods are intended to be non-blocking operations. An await expression in an async method doesn't block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.

What is the use of await task yield?

The await Task.Yield() construct does a fairly simple thing – it interrupts the current method and immediately schedules its continuation in the current synchronization context. This design is used for different purposes. First , this construct can be used to immediately return control to the calling code.

How to yield control of a task to another task?

Instead, call Task.Yield () to yield control to another task. await Task.Delay (...) is a drop-in replacement for Thread.Sleep () within an async method.

What is the difference between await and result in a task?

The first one never seems to end. await asynchronously unwraps the result of your task, whereas just using Result would block until the task had completed. See this explanantion from Jon Skeet.

Why “ awaiting task”?

In this article we will see why “ await Task” is almost always the right choice, even if highly disruptive. Thread pool contention is a well-known challenge to seasoned developers. Services should process work at the same rate as they receive it. If they aren’t then they drag a bunch of additional work that slows down the system:


2 Answers

Consider the case when you want your async task to return a value.

Existing synchronous method:

public int DoSomething() {     return SomeMethodThatReturnsAnInt(); } 

To make async, add async keyword and change return type:

public async Task<int> DoSomething() 

To use Task.Factory.StartNew(), change the one-line body of the method to:

// start new task var task = Task<int>.Factory.StartNew(     () => {         return SomeMethodThatReturnsAnInt();     },     CancellationToken.None,     TaskCreationOptions.None,     TaskScheduler.FromCurrentSynchronizationContext() );  // await task, return control to calling method await task;  // return task result return task.Result; 

vs. adding a single line if you use await Task.Yield()

// this returns control to the calling method await Task.Yield();  // otherwise synchronous method scheduled for async execution by the  // TaskScheduler of the calling thread return SomeMethodThatReturnsAnInt(); 

The latter is far more concise, readable, and really doesn't change the existing method much.

like image 130
Moho Avatar answered Sep 18 '22 14:09

Moho


Task.Yield() is great for "punching a hole" in an otherwise synchronous part of an async method.

Personally I've found it useful in cases where I have a self-cancelling async method (one which manages its own corresponding CancellationTokenSource and cancels the previously created instance on each subsequent call) that can be called multiple times within an extremely short time period (i.e. by interdependent UI elements' event handlers). In such a situation using Task.Yield() followed by an IsCancellationRequested check as soon as the CancellationTokenSource is swapped out can prevent doing potentially expensive work whose results will end up discarded anyway.

Here's an example where only the last queued call to SelfCancellingAsync gets to perform expensive work and run to completion.

using System; using System.Threading; using System.Threading.Tasks;  namespace TaskYieldExample {     class Program     {         private static CancellationTokenSource CancellationTokenSource;          static void Main(string[] args)         {             SelfCancellingAsync();             SelfCancellingAsync();             SelfCancellingAsync();              Console.ReadLine();         }          private static async void SelfCancellingAsync()         {             Console.WriteLine("SelfCancellingAsync starting.");              var cts = new CancellationTokenSource();             var oldCts = Interlocked.Exchange(ref CancellationTokenSource, cts);              if (oldCts != null)             {                 oldCts.Cancel();             }              // Allow quick cancellation.             await Task.Yield();              if (cts.IsCancellationRequested)             {                 return;             }              // Do the "meaty" work.             Console.WriteLine("Performing intensive work.");              var answer = await Task                 .Delay(TimeSpan.FromSeconds(1))                 .ContinueWith(_ => 42, TaskContinuationOptions.ExecuteSynchronously);              if (cts.IsCancellationRequested)             {                 return;             }              // Do something with the result.             Console.WriteLine("SelfCancellingAsync completed. Answer: {0}.", answer);         }     } } 

The goal here is to allow the code which executes synchronously on the same SynchronizationContext immediately after the non-awaited call to the async method returns (when it hits its first await) to change the state that affects the execution of the async method. This is throttling much like that achieved by Task.Delay (i'm talking about a non-zero delay period here), but without the actual, potentially noticeable delay, which can be unwelcome in some situations.

like image 24
Kirill Shlenskiy Avatar answered Sep 18 '22 14:09

Kirill Shlenskiy