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

C#中重复调用API并并发处理数据的问题排查

C#分页API并发处理问题排查与修复

问题场景

调用分页API时,期望获取当前数据块后立即处理,同时请求下一页数据,但当前代码是串行执行:等待API返回→处理数据→再请求下一页,完全没实现并发效果。

原代码

JArray jsonObjects = new JArray();

Task.Run(async () =>
{
    jsonObjects = await GetObjectsJSONAsync();
}).GetAwaiter().GetResult();
private async Task<JArray> GetObjectsJSONAsync()
{
    /*
     * HttpClient setup here
     */

    var response = "";
    var headers = "";
    var total = 0;
    JArray productsFromURL = new JArray();
    HttpResponseMessage result = await client.GetAsync("/products/skus/");
    if (result.IsSuccessStatusCode)
    {
        headers = result.Headers.GetValues("Link").FirstOrDefault();
        response = await result.Content.ReadAsStringAsync();
        jsonObjectsFromURL = JArray.Parse(response);
        ProcessObjects(productsFromURL); // 这里存在bug:传了空的productsFromURL,应该传jsonObjectsFromURL
        while (headers.Contains("rel=\"next\"")) //while header contains next link
        {
            var url = headers.Split(';')[0].Replace("<", "").Replace(">", "");
            result = await client.GetAsync(url);
            try
            {
                response = await result.Content.ReadAsStringAsync();
                jsonObjectsFromURL = JArray.Parse(response);
                ProcessObjects(jsonObjectsFromURL); //adds processed objects to a ConcurrentBag
                headers = result.Headers.GetValues("Link").FirstOrDefault();
            }
            catch (Exception e)
            {
                //This means that there are no more pages to get
                headers = "";
            }
        }
    }

    return jsonObjectsFromURL; //dont care about the return here
}

问题分析

原代码的核心问题是所有操作串行执行:

  1. 先await请求当前页,等待返回
  2. 处理当前页数据
  3. 再await请求下一页,循环往复
    整个流程中,处理数据和请求下一页完全没有并行,浪费了等待API响应的时间。

另外原代码还有个明显bug:第一页处理时传了空的productsFromURL,应该传解析后的jsonObjectsFromURL。

修复方案

要实现处理当前页和请求下一页的并发,核心思路是让数据处理和下一页请求同时进行:发起下一页请求的同时,处理当前页的数据,利用等待API响应的时间来处理数据。

修改后的代码如下:

// 外层调用简化,无需接收返回值
Task.Run(async () =>
{
    await GetObjectsJSONAsync();
}).GetAwaiter().GetResult();
private async Task GetObjectsJSONAsync() // 不需要返回值,结果存入ConcurrentBag
{
    /* HttpClient setup here */

    HttpResponseMessage result = await client.GetAsync("/products/skus/");
    if (!result.IsSuccessStatusCode)
        return;

    var headers = result.Headers.GetValues("Link").FirstOrDefault();
    var response = await result.Content.ReadAsStringAsync();
    var currentPageData = JArray.Parse(response);

    // 启动当前页的处理任务,不等待完成
    Task processingTask = Task.Run(() => ProcessObjects(currentPageData));

    while (headers?.Contains("rel=\"next\"") == true)
    {
        // 解析下一页URL,先发起下一页请求(不await,让请求与当前页处理并行)
        var nextUrl = headers.Split(';')[0].Trim('<', '>');
        Task<HttpResponseMessage> nextPageRequestTask = client.GetAsync(nextUrl);

        // 等待当前页处理完成(若允许处理任务后台持续执行,也可跳过此等待,依业务需求而定)
        await processingTask;

        // 等待下一页请求结果
        result = await nextPageRequestTask;
        if (!result.IsSuccessStatusCode)
            break;

        // 解析下一页数据
        response = await result.Content.ReadAsStringAsync();
        currentPageData = JArray.Parse(response);
        headers = result.Headers.GetValues("Link").FirstOrDefault();

        // 启动下一页的处理任务
        processingTask = Task.Run(() => ProcessObjects(currentPageData));
    }

    // 等待最后一页的处理任务完成,避免程序退出时数据未处理完毕
    await processingTask;
}

关键修改点

  1. 并发执行请求与处理:在处理当前页的同时发起下一页的API请求,充分利用等待响应的时间
  2. 修正参数错误:修复了第一页处理时传空数组的bug
  3. 移除无用返回值:原返回值未被使用,直接删除,简化方法签名
  4. 确保最后一页处理完成:循环结束后等待最后一页的处理任务,避免数据丢失

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:20:00