我不确定我应该如何混合plinq和async-await
。假设我有以下界面
public interface IDoSomething (
Task Do();
}
我有一个列表,我想并行执行这些列表并能够await
完成所有这些。
public async Task DoAll(IDoSomething[] doers) {
//Execute all doers in parallel ideally using plinq and
//continue when all are complete
}
如何实现?我不确定如何从并行linq转到任务,反之亦然。
我对异常处理并不十分担心。理想情况下,第一个会触发并打破整个过程,因为我打算在出错时丢弃整个过程。
编辑:很多人都在说Task.WaitAll
。我意识到这一点,但我的理解(除非有人能证明不是这样)是因为它不会主动将你的东西并行化到多个可用的处理器核心。我特别要求的是双重的 -
如果I await
Plinq Action中的Task
确实可以摆脱很多优势,因为它会安排一个新线程吗?
如果我doers.AsParallel().ForAll(async d => await d.Do())
平均需要大约5秒钟,那我怎么不在此期间转动调用线程呢?
答案 0 :(得分:7)
您正在寻找的是:
public Task DoAllAsync(IEnumerable<IDoSomething> doers)
{
return Task.WhenAll(doers.Select(doer => Task.Run(() => doer.Do())));
}
使用Task.Run
将使用ThreadPool
线程并行执行async
方法Do
的每个同步部分,而Task.WhenAll
异步等待异步部分同时执行的一起。
如果您在这些async
方法(例如await
之前的部分)中有大量同步部分,那么仅这是一个好主意,例如:
async Task Do()
{
for (int i = 0; i < 10000; i++)
{
Math.Pow(i,i);
}
await Task.Delay(10000);
}
否则,不需要并行性,您可以同时触发异步操作并使用Task.WhenAll
等待所有返回的任务:
public Task DoAllAsync(IEnumerable<IDoSomething> doers)
{
return Task.WhenAll(doers.Select(doer => doer.Do()));
}
答案 1 :(得分:1)
public async Task DoAll(IDoSomething[] doers) {
//using ToArray to materialize the query right here
//so we don't accidentally run it twice later.
var tasks = doers.Select(d => Task.Run(()=>d.Do())).ToArray();
await Task.WhenAll(tasks);
}