如何在C#的for循环中并发运行异步函数并捕获所有错误
问题分析与解决方案
你的代码存在两个核心问题,导致无法捕获所有异常甚至出现未处理异常:
- 同步异常直接抛出:如果
SomeAsyncFunc在执行到第一个await之前就抛出异常(比如同步逻辑出错),这个异常会在调用SomeAsyncFunc(item.Index)时直接同步抛出,不会被包装到Task中,自然无法被后续的try/catch捕获。 Task.WhenAll仅抛出第一个异常:即使所有异常都是异步抛出的,await Task.WhenAll也只会将第一个发生的异常抛进catch块,其他任务的异常会被忽略,无法全部打印。
修复方案:为每个任务单独捕获异常并收集结果
通过包装每个异步任务,确保同步/异步异常都被捕获,同时收集所有任务的执行状态,最终遍历输出所有错误:
public async Task RunEachItem() { var tasks = new List<Task<(int ItemIndex, Exception Error)>>(); foreach (var item in Items) { // 捕获循环变量,避免闭包陷阱 int itemIndex = item.Index; tasks.Add(RunTaskWithErrorCapture(itemIndex)); } // 等待所有任务完成,获取所有结果 var executionResults = await Task.WhenAll(tasks); // 遍历所有结果,打印错误信息 foreach (var result in executionResults) { if (result.Error != null) { Console.WriteLine($"项 {result.ItemIndex} 执行出错:{result.Error.Message}"); } } } /// <summary> /// 包装异步任务,捕获所有异常并返回执行结果 /// </summary> private async Task<(int ItemIndex, Exception Error)> RunTaskWithErrorCapture(int index) { try { await SomeAsyncFunc(index); return (index, null); } catch (Exception ex) { return (index, ex); } } public async Task SomeAsyncFunc(int index) { // 模拟异步处理逻辑 await Task.Delay(50); throw new Exception($"some error for item {index}"); }
方案说明
- 同步/异步异常全覆盖:每个任务都被包裹在独立的
try/catch中,无论是SomeAsyncFunc里的同步逻辑异常,还是异步阶段抛出的异常,都会被捕获并包装到返回值中。 - 避免闭包陷阱:在循环内部捕获
item.Index到局部变量,防止所有任务共享循环变量的引用,导致最终使用的都是最后一个项的索引。 - 收集所有错误:通过返回值记录每个任务的执行状态,最终遍历所有结果即可输出全部错误信息,不会遗漏任何异常。
内容的提问来源于stack exchange,提问作者jumpingSloth
相关产品推荐
相关产品推荐

