As expected the list of tasks asynchronously using LINQ?

I have a list of tasks that I created as follows:

public async Task<IList<Foo>> GetFoosAndDoSomethingAsync() { var foos = await GetFoosAsync(); var tasks = foos.Select(async foo => await DoSomethingAsync(foo)).ToList(); ... } 

Using .ToList() , all tasks must begin. Now I want to wait for them to complete and return the results.

It works in the previous block ... :

 var list = new List<Foo>(); foreach (var task in tasks) list.Add(await task); return list; (); var list = new List<Foo>(); foreach (var task in tasks) list.Add(await task); return list; 

He does what I want, but it seems quite awkward. I would rather have written something more simple:

 return tasks.Select(async task => await task).ToList(); 

... but it will not compile. What am I missing? Or is it just impossible to express it?

+58
# c linq the async-the await
18 February. '14 at 23:52
source share
5 answers

LINQ does not work very well with the code async , but you can do it:

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

If your tasks return the same type of value that you can even do this:

 var results = await Task.WhenAll(tasks); 

which is quite nice. WhenAll returns an array, so I think that your method can directly return results:

 return await Task.WhenAll(tasks); 
+91
Feb 18. '14 23:57
source share

To expand the answer Stephen, I created the following extension method to save Freestyle LINQ. Then you can do

 await someTasks.WhenAll() namespace System.Linq { public static class IEnumerableExtensions { public static Task<T[]> WhenAll<T>(this IEnumerable<Task<T>> source) { return Task.WhenAll(source); } } } WhenAll <T> (this IEnumerable <Task <T >> source) await someTasks.WhenAll() namespace System.Linq { public static class IEnumerableExtensions { public static Task<T[]> WhenAll<T>(this IEnumerable<Task<T>> source) { return Task.WhenAll(source); } } } 
+5
April 8. '15 20:05
source share

Use Task.WaitAll or Task.WhenAll depending on which one is approriate.

+2
18 Feb. '14 23:54
source share

Task.WhenAll should do the trick here.

+1
18 February. '14 23:57
source share

One problem with Task.WhenAll is that it will create a parallelism. In most cases it can be even better, but sometimes you want to avoid this. For example, reading data packets from the database and send the data to some remote web service. You do not want to download all games in memory, but get into the database after the processing of the previous batch. So you have to break the asynchrony. Here is an example:

 var events = Enumerable.Range(0, totalCount/ batchSize) .Select(x => x*batchSize) .Select(x => dbRepository.GetEventsBatch(x, batchSize).GetAwaiter().GetResult()) .SelectMany(x => x); foreach (var carEvent in events) { } ) var events = Enumerable.Range(0, totalCount/ batchSize) .Select(x => x*batchSize) .Select(x => dbRepository.GetEventsBatch(x, batchSize).GetAwaiter().GetResult()) .SelectMany(x => x); foreach (var carEvent in events) { } , batchSize) .GetAwaiter (). GetResult ()) var events = Enumerable.Range(0, totalCount/ batchSize) .Select(x => x*batchSize) .Select(x => dbRepository.GetEventsBatch(x, batchSize).GetAwaiter().GetResult()) .SelectMany(x => x); foreach (var carEvent in events) { } 

Note .GetAwaiter (). GetResult () converts it into synchronization. DB managed lazily only after the event batch processing.

0
June 29. '17 at 2:09
source share



All Articles