考虑这段代码,其中有一些工作在for循环中完成,然后是一个递归调用来处理子项。我想将DoSomething(item)和GetItems(id)转换为异步方法,但如果我在这里等待它们,for循环将等待每次迭代完成后再继续,基本上失去了并行处理的好处。我怎样才能提高这种方法的性能?是否可以使用async / await做到这一点?
public void DoWork(string id)
{
var items = GetItems(id); //takes time
if (items == null)
return;
Parallel.ForEach(items, item =>
{
DoSomething(item); //takes time
DoWork(item.subItemId);
});
}
答案 0 :(得分:3)
您可以创建一系列任务,然后使用Task.WhenAll
等待所有任务完成,而不是使用Parallel.ForEach
遍历项目。由于您的代码也涉及递归,因此稍微复杂一点,您需要将DoSomething
和DoWork
合并到一个我恰当地命名为DoIt
的方法中:
async Task DoWork(String id) {
var items = GetItems(id);
if (items == null)
return;
var tasks = items.Select(DoIt);
await Task.WhenAll(tasks);
}
async Task DoIt(Item item) {
await DoSomething(item);
await DoWork(item.subItemId);
}
混合Parallel.ForEach
和async / await是一个坏主意。 Parallel.ForEach
将允许您的代码并行执行,对于计算密集但可并行化的算法,您将获得最佳性能。但是,async / await允许您的代码并发执行,例如,在IO操作中阻止的重用线程。
简化Parallel.ForEach
将设置与计算机上具有CPU内核一样多的线程,然后对要迭代的项进行分区,以便跨这些线程执行。所以Parallel.ForEach
应该在你的调用堆栈的底部使用一次,然后它将把工作分散到多个线程并等待它们完成。在每个线程内以递归方式调用Parallel.ForEach
只是疯狂,根本无法提高性能。