如何在C#的List.ForEach中实现异步并行调用?
实现4个Chunk并行异步上传的正确方式
你的问题核心在于没有正确处理异步方法的等待和并行执行——原来的代码用了回调式异步+ForEach,既无法追踪所有任务的完成状态,也不能妥善处理异常。下面一步步给你改出正确的实现:
第一步:重构异步上传方法为返回Task的规范异步方法
首先把UploadChunkToServer改成符合C#异步规范的方法,用await替代回调,这样能更好地控制流程和捕获异常:
// 按规范给异步方法加Async后缀 private async Task UploadChunkToServerAsync(UserCustomFile chunk) { var client = new RestClient(Helper.GetServerURL()); var request = new RestRequest("api/fileupload/savechunk", Method.POST); request.AddHeader("Content-type", "application/json"); request.RequestFormat = RestSharp.DataFormat.Json; request.AddJsonBody(chunk); // 用await替代回调,直接获取响应 var response = await client.ExecuteAsync(request); if (response.StatusCode != System.Net.HttpStatusCode.OK) { throw new Exception(response.ErrorMessage ?? "Chunk upload failed with unknown error"); } else { // 注意:如果ChunkStatuses是普通List<T>,多线程并行Add会有线程安全问题 // 建议换成ConcurrentBag<T>这类线程安全集合 ChunkStatuses.Add(chunk.ChunkID); } }
第二步:用Task.WhenAll实现并行上传并等待全部完成
把原来的ForEach调用改成创建任务集合,再用Task.WhenAll等待所有并行任务完成:
// 确保调用这个逻辑的方法本身是异步的(加async关键字,返回Task/Task<T>) if (DataQueue.Count == NumberofChunksToRead) { var chunks = DataQueue.ToList(); // 为每个Chunk创建上传任务 var uploadTasks = chunks.Select(chunk => UploadChunkToServerAsync(chunk)).ToList(); try { // 等待所有上传任务并行完成 await Task.WhenAll(uploadTasks); // 到这里所有Chunk都上传成功了,可以做后续逻辑 Console.WriteLine("All chunks uploaded successfully!"); } catch (Exception ex) { // 捕获任何一个上传任务抛出的异常,做错误处理 Console.WriteLine($"Upload failed: {ex.Message}"); } }
为什么原来的方式不行?
- 回调式异步的缺陷:原来的
UploadChunkToServer是void方法,内部用回调处理异步结果,这种方式下你无法知道所有上传任务何时完成,而且回调里抛出的异常会被异步上下文悄悄吞掉,根本无法捕获。 - async void的反模式:如果直接给
ForEach的lambda加async,会变成async void方法——这是C#异步编程的反模式,调用方无法等待它完成,异常也难以追踪。
额外注意事项
- 线程安全:如果
ChunkStatuses是普通的List<T>,多个并行任务同时调用Add会导致线程安全问题,建议替换成System.Collections.Concurrent.ConcurrentBag<T>。 - 异步方法的传播:调用上述逻辑的方法必须是异步的(比如事件处理程序可以用
async void,其他方法建议返回Task),否则无法使用await。
内容的提问来源于stack exchange,提问作者user1144596
相关产品推荐
相关产品推荐

