使用AsParallel.ForAll搭配异步代码未等待完成,是否为预期行为?
关于AsParallel().ForAll()在异步场景下不阻塞的问题
首先明确:AsParallel().ForAll()本身是同步阻塞方法,在传入同步委托时,它会等待所有并行任务执行完成后才会继续后续代码——这也是你同步场景下运行正常的原因。
但你改成异步后出现"Done!"先输出的情况,核心问题出在你传给ForAll的是异步lambda(async () => { ... }):
- ForAll接受的是
Action<T>类型的委托,而异步lambda会被隐式转换为async void方法(因为Action没有返回值)。 async void是异步编程中的特殊情况:调用方无法等待它的执行完成,调用后会立即返回。所以ForAll会误以为每个委托都已经执行完毕(实际只是启动了异步操作),直接继续执行后续的"Done!"代码,而异步任务还在后台运行。
这不是你的操作错误,而是对异步委托与PLINQ结合的特性不熟悉,这种行为是async void的预期表现。
正确的异步并行处理方式
如果需要在并行场景中处理异步操作,不要用AsParallel().ForAll(),推荐以下两种方式:
方式1:使用Parallel.ForEachAsync(.NET 6+支持)
这是官方推荐的异步并行遍历方法,能正确等待所有异步任务完成:
await Parallel.ForEachAsync(Enumerable.Range(1, 5), async (num, ct) => { await Task.Delay(100, ct); Console.WriteLine(num); }); Console.WriteLine("Done!");
方式2:PLINQ结合Task.WhenAll
通过PLINQ生成异步任务集合,再用Task.WhenAll等待所有任务完成:
var asyncTasks = Enumerable.Range(1, 5).AsParallel().Select(async num => { await Task.Delay(100); Console.WriteLine(num); }); await Task.WhenAll(asyncTasks); Console.WriteLine("Done!");
内容的提问来源于stack exchange,提问作者GoldieLocks
相关产品推荐
相关产品推荐

