使用async/await并行执行多个长时间运行的任务

问题描述:

我有一个辅助方法返回IEnumerable<string>。随着收藏的增长,它正在大幅减速。我目前的做法是基本上做到以下几点:使用async/await并行执行多个长时间运行的任务

var results = new List<string>(); 
foreach (var item in items) 
{ 
    results.Add(await item.Fetch()); 
} 

我实际上并不确定这是否异步给我任何利益(它肯定不会似乎喜欢它),但是所有的方法堆栈和我的控制器的动作are asynchronous

public async Task<IHttpActionResult> FetchAllItems() 

因为这些代码最终使用我的API,我真的很想并行这些所有的东西,我希望将是巨大的速度提升。我试过.AsParallel:

var results = items 
    .AsParallel() 
    .Select(i => i.Fetch().Result) 
    .AsList(); 
return results; 

而且.WhenAll(返回一个字符串[]):

var tasks = items.Select(i => i.Fetch()); 
return Task<string>.WhenAll<string>(tasks).Result; 

和解雇了所有长时间运行的作业,并依次等待他们的最后努力(希望他们都并行运行,所以在等待一个会让所有其他接近完成):

var tasks = new LinkedList<Task<string>>(); 
foreach (var item in items) 
    tasks.AddLast(item.Fetch()); 

var results = new LinkedList<string>(); 
foreach (var task in tasks) 
    results.AddLast(task.Result); 

在每次测试情况下,需要运行的时间是成正比的ITE的数量女士。这样做没有可辨别的加速。我在使用任务时丢失了什么,并且await/async

+0

异步不会为您提供改进算法性能的好处,相反,它将允许您的主线程(UI)在工作完成时保持响应。 – 2014-10-31 02:49:04

+1

如果任务CPU绑定,应该看到加速比例与CPU数量成正比,除非你的代码有一些东西(比如共享'lock'下的大块代码),它完全阻止它并行运行或者CPU已经处于100%其他处理。 – 2014-10-31 02:54:24

+0

@JohnKoerner:'.AsParallel'会为这些异步任务提供加速吗?我最初开始将我的'foreach'调整为'Parallel.ForEach',然后我走进了一个异步/等待世界。 – user655321 2014-10-31 02:58:36

平行并发之间的差异。并发意味着一次只能做多件事,而并行意味着在多个线程上做不止一件事async非常适合并发性,但不会(直接)帮助您进行并行处理。

作为一般规则,应避免ASP.NET上的并行性。这是因为您所做的任何并行工作(即AsParallel,Parallel.ForEach等)与ASP.NET共享相同的线程池,因此降低了ASP.NET处理其他请求的能力。这会影响Web服务的可伸缩性。最好将线程池留给ASP.NET。

但是,并发性很好 - 特别是异步并发。这是Task.WhenAll进来这样的代码是你应该寻找什么(注意,是Task<T>.Result没有呼叫):

var tasks = items.Select(i => i.Fetch()); 
return await Task<string>.WhenAll<string>(tasks); 

鉴于你的其他代码样本,这将有利于通过您的通话时同时运行从Fetch开始,并用await替换所有Result调用。这可能是(部分)你的问题,因为Result强制同步执行。

另一个可能的问题是正在提取的底层资源不支持并发访问,或者可能存在您不知道的限制。例如,如果Fetch从其他Web服务检索数据,请检查System.Net.ServicePointManager.DefaultConnectionLimit

+0

也许我只是不想'async' /'await',我想在调试器中看到结果本身而不是任务。如果我的整个调用链(一直到控制器的动作)都是'async',我可以简单地实现'WhenAll'(如你的代码示例中)并且改进我当前的'foreach'实现的性能吗? – user655321 2014-10-31 15:34:12

+0

是的,只要底层资源允许并发访问并且不存在限制。 – 2014-10-31 15:39:21