如何使用LINQasynchronous地等待任务列表?
我有一个我创build的任务列表,如下所示:
public async Task<IList<Foo>> GetFoosAndDoSomethingAsync() { var foos = await GetFoosAsync(); var tasks = foos.Select(async foo => await DoSomethingAsync(foo)).ToList(); ... }
通过使用.ToList()
,任务应该都开始。 现在我想等待完成并返回结果。
这工作在上面...
块:
var list = new List<Foo>(); foreach (var task in tasks) list.Add(await task); return list;
它做我想要的,但这似乎相当笨拙。 我宁愿写这样简单的东西:
return tasks.Select(async task => await task).ToList();
…但这不能编译。 我错过了什么? 还是这样expression事物是不可能的?
LINQ与async
代码无法正常工作,但是你可以这样做:
var tasks = foos.Select(DoSomethingAsync).ToList(); await Task.WhenAll(tasks);
如果你的任务都返回相同types的值,那么你甚至可以这样做:
var results = await Task.WhenAll(tasks);
这是相当不错的。 WhenAll
返回一个数组,所以我相信你的方法可以直接返回结果:
return await Task.WhenAll(tasks);
为了扩大Stephen的回答,我创build了下面的扩展方法来保持LINQ的stream畅风格 。 你可以这样做
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); } } }
使用Task.WaitAll
或Task.WhenAll
任何适用的。
任务。什么时候都应该这样做。
Task.WhenAll的一个问题是它会产生一个并行性。 在大多数情况下,它可能会更好,但有时候你想避免它。 例如,从数据库批量读取数据并将数据发送到某个远程Web服务。 您不希望将所有批次加载到内存中,而是在上一批处理完成之后再次加载数据库。 所以,你必须打破asynchronous性。 这里是一个例子:
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) { }
注意.GetAwaiter()。GetResult()将其转换为同步。 数据库只会在事件的batchSize被处理一次后才会被打到。