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

.NET Core 6中并行调用ASP.NET Core Web API端点的最优方案

.NET Core 6批量调用端点的高效实现方案

你的思路是对的,Task.WhenAll确实可以用来并行处理多个请求,大幅缩短总耗时,但直接发起18000个并发请求会引发资源耗尽、目标服务器过载等问题,需要结合并发控制来优化。

核心问题分析

直接创建18000个Task并执行Task.WhenAll会导致:

  • 本地Socket端口快速耗尽(系统可用临时端口数量有限)
  • 目标端点承受远超其处理能力的请求,触发限流、超时甚至崩溃
  • 大量并发请求可能导致本地线程池过载,降低整体性能

优化实现方案

通过SemaphoreSlim控制并发请求数量,配合Task.WhenAll实现高效批量调用,同时复用HttpClient避免资源浪费。

代码示例

using System.Net.Http;
using System.Threading;
using System.Collections.Generic;
using System.Linq;

// 配置参数
const int TotalRequests = 18000;
const int MaxConcurrentRequests = 100; // 根据目标服务器性能调整
var targetEndpoint = "https://your-api-endpoint.com/target";

// 复用HttpClient(ASP.NET Core中推荐通过IHttpClientFactory依赖注入获取)
using var httpClient = new HttpClient();
var semaphore = new SemaphoreSlim(MaxConcurrentRequests);
var requestResults = new List<RequestResult>(TotalRequests);

// 生成所有请求任务
var tasks = Enumerable.Range(0, TotalRequests).Select(async requestId =>
{
    await semaphore.WaitAsync();
    try
    {
        var timer = System.Diagnostics.Stopwatch.StartNew();
        var response = await httpClient.GetAsync(targetEndpoint);
        timer.Stop();

        var responseContent = await response.Content.ReadAsStringAsync();
        requestResults.Add(new RequestResult
        {
            RequestId = requestId,
            IsSuccess = response.IsSuccessStatusCode,
            StatusCode = response.StatusCode,
            ResponseContent = responseContent,
            ElapsedMs = timer.ElapsedMilliseconds
        });
    }
    catch (Exception ex)
    {
        requestResults.Add(new RequestResult
        {
            RequestId = requestId,
            IsSuccess = false,
            ErrorMsg = ex.Message
        });
    }
    finally
    {
        semaphore.Release();
    }
});

// 等待所有请求完成
await Task.WhenAll(tasks);

// 处理并记录结果(示例:输出到控制台,实际可写入日志/数据库)
foreach (var result in requestResults)
{
    var logMsg = result.IsSuccess 
        ? $"请求{result.RequestId} 成功 | 耗时: {result.ElapsedMs}ms | 状态码: {result.StatusCode}"
        : $"请求{result.RequestId} 失败 | 错误: {result.ErrorMsg}";
    Console.WriteLine(logMsg);
}

// 结果存储模型
public class RequestResult
{
    public int RequestId { get; set; }
    public bool IsSuccess { get; set; }
    public System.Net.HttpStatusCode? StatusCode { get; set; }
    public string? ResponseContent { get; set; }
    public long? ElapsedMs { get; set; }
    public string? ErrorMsg { get; set; }
}

关键注意事项

  • 复用HttpClient:不要每次请求都创建新的HttpClient,避免Socket资源泄漏,ASP.NET Core中优先使用IHttpClientFactory
  • 调整并发数:根据目标服务器的QPS限制和本地系统配置,测试出最优的MaxConcurrentRequests值(比如50-200之间)
  • 异常处理:每个请求单独捕获异常,确保单个请求失败不会影响其他任务执行
  • 结果记录:建议使用专业日志框架(如Serilog、NLog)代替控制台输出,方便后续分析请求成功率、响应耗时等数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 14:12:04