You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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}");
    }
}

为什么原来的方式不行?

  1. 回调式异步的缺陷:原来的UploadChunkToServer是void方法,内部用回调处理异步结果,这种方式下你无法知道所有上传任务何时完成,而且回调里抛出的异常会被异步上下文悄悄吞掉,根本无法捕获。
  2. async void的反模式:如果直接给ForEach的lambda加async,会变成async void方法——这是C#异步编程的反模式,调用方无法等待它完成,异常也难以追踪。

额外注意事项

  • 线程安全:如果ChunkStatuses是普通的List<T>,多个并行任务同时调用Add会导致线程安全问题,建议替换成System.Collections.Concurrent.ConcurrentBag<T>。
  • 异步方法的传播:调用上述逻辑的方法必须是异步的(比如事件处理程序可以用async void,其他方法建议返回Task),否则无法使用await。

内容的提问来源于stack exchange,提问作者user1144596

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:52:31