Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different methods of completing an "empty" async Task

Tags:

c#

async-await

I'm using a library that has both a synchronous and an async version of a Reconcile method.

The methods take 2 IEnumerables, and 3 delegates that get called for items that are Added, Modified, or Deleted from the 2nd list based on values from the first.

My code is currently working with the synchronous version, and I'd like to convert it to using the async version.

Since I don't actually need to do any work in the delegate for deleting, I'm passing in (item) => {} for the deletedAction argument.

I've found several different versions of how to convert that in to an "empty" async delegate scattered around the internet, and across StackOverflow, but I'm not sure of the difference between them, or which way is the most correct.

What are the differences between these methods of sending an "empty" async delegate as an argument, and which of them is the current "most correct" way? Is there a better way that I have missed?

  1. async (item) => {await Task.CompletedTask;}
  2. async (item) => {await Task.FromResult(0);}
  3. async (item) => {await Task.Yield;}
  4. async (item) => {await Task.Delay(0);} (this one seems like a bad choice, but I'm including it for completeness)

They all seem to be working, except for Task.CompletedTask, but that is because the framework I'm using is the 4.5 version of the .Net Framework, and it doesn't exist in that version.

like image 415
Bradley Uffner Avatar asked Mar 06 '18 15:03

Bradley Uffner


People also ask

Can we use async without task?

Async code can be used for both I/O-bound and CPU-bound code, but differently for each scenario. Async code uses Task<T> and Task , which are constructs used to model work being done in the background. The async keyword turns a method into an async method, which allows you to use the await keyword in its body.

What are async methods?

An async method runs synchronously until it reaches its first await expression, at which point the method is suspended until the awaited task is complete. In the meantime, control returns to the caller of the method, as the example in the next section shows.

Can async method return null?

Task represents the execution of the asynchronous method, so for an asynchronous method to return a null task is like telling the calling code "you didn't really just call this method" when of course it did. So, a Task / Task<T> returned from a method should never, ever be null .


1 Answers

So none of them are correct. What you should be doing is:

item => Task.CompletedTask

Or, when on an older version of the framework:

item => Task.FromResult(0)

You have no reason to make the method async just to await an already completed task. It's just adding overhead of the state machine in order to accomplish nothing.

Using Delay is just going through an extra layer of indirection before returning a completed task. It's adding nothing useful except obscuring the fact that you're trying to return a completed Task. It's also relying on an undocumented implementation detail that Delay returns a completed task when the timeout is 0, which is something to be avoided where possible.

Using Yield is by far the worst. The whole point of Yield is that it won't be observed as being completed right away. The goal of Yield is to result in the continuation being added and fired, rather than the task being observed as being completed immediately. It exists specifically to avoid the optimization that you want to take advantage of.

like image 51
Servy Avatar answered Nov 12 '22 01:11

Servy