Almost every SO's answer regarding this topic , states that :
LINQ doesn't work perfectly with async
Also :
I recommend that you not think of this as "using async within LINQ"
But in Stephen's book there is a sample for :
Problem: You have a collection of tasks to await, and you want to do some processing on each task after it completes. However, you want to do the processing for each one as soon as it completes, not waiting for any of the other tasks.
One of the recommended solutions was :
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks.
Task<int> taskA = DelayAndReturnAsync(2);
Task<int> taskB = DelayAndReturnAsync(3);
Task<int> taskC = DelayAndReturnAsync(1);
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = tasks.Select(async t =>
{
var result = await t;
Trace.WriteLine(result);
}).ToArray();
// Await all processing to complete
await Task.WhenAll(processingTasks);
}
Question #1:
I don't understand why now async
inside a LINQ statement - does work . Didn't we just say "don't think about using async
within LINQ" ?
Question #2:
When the control reaches the await t
here — What is actually happen? Does the control leaves the ProcessTasksAsync
method ? or does it leaves the anonymous method and continue the iteration ?
Evolution of An Async LINQ operator LINQ (Language-Integrated Query) has been around for quite a while in the world of.NET (since.NET Framework 3.5 and C# 3.0) but recently async streams (i.e. IAsyncEnumerable<T>) were added to.NET and with them came async LINQ.
Query syntax is similar to SQL (Structured Query Language) for the database. It is defined within the C# or VB code. The LINQ query syntax starts with from keyword and ends with select keyword. The following is a sample LINQ query that returns a collection of strings which contains a word "Tutorials".
When a method is async the naming convention suggest that you append "Async" to your method name. By convention, you append "Async" to the names of methods that have an Async or async modifier.
A LINQ query is often a little longer horizontally than your usual code. When you now try to give every lambda variable a good name, your line will certainly get way longer, you might use your variable repeatedly, and you might find it harder to break your code.
I don't understand why now async inside a LINQ statement - does work . Didn't we just say "don't think about using async within LINQ" ?
async
mostly doesn't work with LINQ because IEnumerable<T>
extensions don't always infer the delegate type properly and defer to Action<T>
. They have no special understanding of the Task
class. This means the actual async delegate becomes async void
, which is bad. In the case of Enumerable.Select
, we have an overload which returns a Func<T>
(which in turn will be Func<Task>
in our case), which is equivalent to async Task
, hence it works fine for async use-cases.
When the control reaches the await t here — What is actually happen? Does the control leaves the ProcessTasksAsync method ?
No, it doesn't. Enumerable.Select
is about projecting all elements in the sequence. This means that for each element in the collection, await t
which will yield control back to the iterator, which will continue iterating all elements. That's why you later have to await Task.WhenAll
, to ensure all elements have finished execution.
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