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

.NET Core使用Task获取多页面内容长度结果错误,如何实现多线程并行?

问题原因分析
  • 第一个写法结果错误的核心原因是循环变量捕获问题:C#中for循环的迭代变量i是整个循环作用域共享的,Task.Run的lambda属于延迟执行,等到实际执行时大概率循环已经跑完,i已经变成了101,所有请求的url都是view/101,自然输出结果相同。
  • 第二个写法串行的原因是每次循环都await了Task.Run的结果,必须等上一个任务执行完才会进入下一次循环,所以只能串行执行。
  • 额外优化提示:原代码中每次请求都实例化HttpClient会导致端口耗尽问题,官方建议全局复用单例HttpClient,不影响作业要求的前提下可以优化。
正确实现(符合仅用Task的作业要求)
// 全局复用HttpClient,不影响作业逻辑的前提下可优化,也可以保留原方法的实例化逻辑
private static readonly HttpClient _httpClient = new HttpClient();

public static async Task GetContentLengthAsync(string url)
{
    var httpResponse = await _httpClient.GetAsync(url);
    if (httpResponse.IsSuccessStatusCode)
    {
        var page = await httpResponse.Content.ReadAsStringAsync();
        Console.WriteLine($"{url} 内容长度:{page.Length}");
    }
    else
    {
        Console.WriteLine($"{url} 请求失败,状态码:{httpResponse.StatusCode}");
    }
}

public static async Task GetLengthsAsync()
{
    List<Task> allTasks = new List<Task>();
    for (int i = 1; i <= 100; i++)
    {
        // 循环内定义局部变量,每次迭代生成独立的变量副本,避免闭包捕获共享的迭代变量i
        int currentPage = i;
        // 只将任务加入集合,不等待,直接进入下一次循环
        allTasks.Add(Task.Run(() => GetContentLengthAsync($"https://www.website.com/view/{currentPage}")));
    }
    // 统一等待所有任务执行完成
    await Task.WhenAll(allTasks);
}
实现说明
  • 局部变量currentPage解决了闭包捕获共享变量的问题,每个任务的url参数不会错乱,结果正确
  • 所有任务会被线程池调度并行执行,充分利用多线程资源,不会出现串行的问题
  • 整个方法是异步的,调用处await GetLengthsAsync()不会阻塞主线程,控制台可以正常响应其他操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 10:06:02