I have an async lambda expression wrapped under Task.Run. However, it looks like I can drop the async and await keywords and they will produce the same result.
t1 = Task.Run(() => DoSomethingExpensiveAsync());
t2 = Task.Run(() => DoSomethingExpensiveAsync());
await Task.WhenAll(t1, t2);
vs
var t1 = Task.Run(async () => await DoSomethingExpensiveAsync());
var t2 = Task.Run(async () => await DoSomethingExpensiveAsync());
await Task.WhenAll(t1, t2);
Unlike StartNew , Task. Run is async -aware.
Use of async and await enables the use of ordinary try / catch blocks around asynchronous code. Note: The await keyword is only valid inside async functions within regular JavaScript code. If you use it outside of an async function's body, you will get a SyntaxError .
Asynchronous programming with async and await follows the task-based asynchronous pattern. You can use the await operator only in a method, lambda expression, or anonymous method that is modified by the async keyword.
The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.
There are actually three variants.
var task = Task.Run(() => DoSomethingExpensiveAsync());
^ This one declares a new anonymous non-async function that calls DoSomethingExpensiveAsync()
and returns its Task
. The compiler compiles this anonymous function and passes it as an argument to Task.Run()
.
var task = Task.Run( async () => await DoSomethingExpensiveAsync() );
^ This one declares a new anonymous async function that calls DoSomethingExpensiveAsync()
. It then returns an incomplete Task
, waits for DoSomethingExpensiveAsync()
to finish, and then signals the task as complete.
var task = Task.Run(DoSomethingExpensiveAsync);
^ This one does not declare a new anonymous function at all. A direct reference to DoSomethingExpensiveAsync
will be passed as an argument to Task.Run()
.
All of these are valid because all three versions return a Task
and therefore match the overload of Task.Run()
that accepts a Func<Task>
.
As a black box, all three calls will end up doing the same thing. However the first two result in a new function being compiled (although I'm not certain it wouldn't be optimized away) and the second one also results in another state machine being created for it.
The difference might be clearer if we rewrite them without using lambda expressions or anonymous functions. The following code does exactly the same thing:
//This is the same as Task.Run( () => DoSomethingExpensiveAsync());
Task Foo()
{
return DoSomethingExpensiveAsync();
}
var task = Task.Run(Foo);
//This is the same as Task.Run(async () => await DoSomethingExpensiveAsync());
async Task Bar()
{
return await DoSomethingExpensiveAsync();
}
var task = Task.Run(Bar);
The difference between these two is that one "elides" tasks while the other doesn't. Stephen Cleary has written a whole blog on the subject.
How come the compiler let me do this and what is happening behind the scene?
The overload of Task.Run
that you're invoking takes a Func<Task>
- that is, a Task
-returning function. It doesn't matter where the Task
comes from; the function just needs to return it from somewhere.
If you pass a delegate without async
and await
, then the delegate is just calling a Task
-returning function and returns that same Task
. If you pass a delegate with async
and await
, then the delegate calls the Task
-returning function and await
s it; the actual Task
returned from the delegate is created by the async
keyword.
In this case, the two are semantically equivalent. Using the async
/await
keywords are a bit less efficient, since the compiler creates a state machine for the async
delegate.
Is there a situation where adding them will make a difference?
Yes. In the general case, you should keep async
and await
. Only remove them in extremely simple "passthrough" situations like the one here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With