Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What actually happens when using async/await inside a LINQ statement?

The following snippet compiles, but I'd expect it to await the task result instead of giving me a List<Task<T>>.

var foo = bars.Select(async bar => await Baz(bar)).ToList()

As pointed out here, you need to use Task.WhenAll:

var tasks = foos.Select(async foo => await DoSomethingAsync(foo)).ToList();
await Task.WhenAll(tasks);

But a comment points out that the async and await inside the Select() is not needed:

var tasks = foos.Select(foo => DoSomethingAsync(foo)).ToList();

A similar question here where someone tries to use an async method inside a Where().

So async and await inside a LINQ statement is legal syntax, but does it do nothing at all or does it have a certain use?

like image 908
user247702 Avatar asked Apr 16 '14 13:04

user247702


People also ask

What happens during async await?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete.

Is Linq asynchronous?

Note that there are no async versions of some LINQ operators such as Where or OrderBy, because these only build up the LINQ expression tree and don't cause the query to be executed in the database. Only operators which cause query execution have async counterparts.

What is the advantage of async await in C#?

The biggest advantage of using async and await is, it is very simple and the asynchronous method looks very similar to a normal synchronous methods. It does not change programming structure like the old models (APM and EAP) and the resultant asynchronous method look similar to synchronous methods.

What is async and await in C# with real time example?

async/await is single thread event based model. Which allows you to run code out-of-order until the line of code await. In Raku it would actually wait at the await . sub example { my $p = do-something-async; say 'next line'; await $p; say 'done awaiting'}; sub do-something-async { return Promise.in(5).


2 Answers

I recommend that you not think of this as "using async within LINQ". Keep in mind what's in-between the two: delegates. Several LINQ operators take delegates, and async can be used to create an asynchronous delegate.

So, when you have an asynchronous method BazAsync that returns a Task:

Task BazAsync(TBar bar);

then this code results in a sequence of tasks:

IEnumerable<Task> tasks = bars.Select(bar => BazAsync(bar));

Similarly, if you use async and await within the delegate, you're creating an asynchronous delegate that returns a Task:

IEnumerable<Task> tasks = bars.Select(async bar => await BazAsync(bar));

These two LINQ expressions are functionally equivalent. There are no important differences.

Just like regular LINQ expressions, the IEnumerable<Task> is lazy-evaluated. Only, with asynchronous methods like BazAsync, you usually do not want accidental double-evaluation or anything like that. So, when you project to a sequence of tasks, it's usually a good idea to immediately reify the sequence. This calls BazAsync for all the elements in the source sequence, starting all the tasks going:

Task[] tasks = bars.Select(bar => BazAsync(bar)).ToArray();

Of course, all we've done with Select is start an asynchronous operation for each element. If you want to wait for them all to complete, then use Task.WhenAll:

await Task.WhenAll(tasks);

Most other LINQ operators do not work as cleanly with asynchronous delegates. Select is pretty straightforward: you're just starting an asynchronous operation for each element.

like image 92
Stephen Cleary Avatar answered Oct 08 '22 12:10

Stephen Cleary


does it have a certain use

Sure. With async and await inside a LINQ statement you can e.g. do something like this:

var tasks = foos.Select( async foo =>
    {
        var intermediate =  await DoSomethingAsync( foo );
        return await DoSomethingElseAsync( intermediate );
    } ).ToList();
await Task.WhenAll(tasks);

Without async/await inside a LINQ statement you're not awaiting anything inside the LINQ statement, so you can't process the result, or await for something else.

Without async/await, in the LINQ statement you're only starting tasks, but not waiting for them to complete. They'll still complete eventually, but it'll happen long after the control will leave the LINQ statement, so you can only access their results after the WhenAll line will complete, but not inside the LINQ statement.

like image 9
Soonts Avatar answered Oct 08 '22 12:10

Soonts