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

如何在C#(.NET7.0)中高效执行100+个API请求

批量发起POST请求的正确实现方案(.NET 7)

现有方案的问题

  • 测试一:一次性创建所有请求任务并等待完成,无并发限制。瞬间发起数千请求会导致目标API过载、本地端口耗尽,最终触发超时;且每次请求新建HttpClient,会造成大量资源浪费和连接池问题。
  • 测试二:循环中逐个await任务,本质是串行执行,完全未利用并发优势,耗时自然过长。
  • 测试三:Parallel.ForEach不兼容异步lambda,传入async lambda会导致方法直接返回,任务后台执行但无法等待完成,无法保证所有请求执行完毕。

正确实现步骤

1. 复用HttpClient(关键优化)

每次请求新建HttpClient会耗尽套接字资源,推荐用.NET内置的IHttpClientFactory管理客户端生命周期,或使用静态HttpClient实例(注意静态实例的配置一致性)。

2. 控制并发数

即使数据库允许无限连接,目标API和本地网络也无法承受数千请求同时发起,必须限制并发量(建议从20-50开始测试,根据实际情况调整)。可使用SemaphoreSlim或.NET 6+新增的Parallel.ForEachAsync。

3. 正确序列化JSON

手动拼接JSON易出现转义错误,改用System.Text.Json自动序列化,避免手动处理字符串转义。

代码实现

修正后的Execute方法(复用HttpClient+正确序列化)

// 在依赖注入容器中注册IHttpClientFactory后注入
private readonly IHttpClientFactory _httpClientFactory;

public SyntaxExecutor(IHttpClientFactory httpClientFactory)
{
    _httpClientFactory = httpClientFactory;
}

public async Task<string> Execute(SyntaxCommand command)
{
    var client = _httpClientFactory.CreateClient();
    client.Timeout = TimeSpan.FromMinutes(10);

    // 使用System.Text.Json自动序列化,避免手动拼接错误
    var requestBody = new
    {
        syntax = command.Syntax,
        replacementVariableId = command.VariableId,
        hierarchyId = command.HierarchyId
    };

    var jsonContent = JsonContent.Create(requestBody);

    try
    {
        var response = await client.PostAsync("https://localhost:44346/SyntaxExecutor", jsonContent);
        response.EnsureSuccessStatusCode(); // 主动触发非2xx状态码的异常
        var responseBody = await response.Content.ReadAsStringAsync();
        return responseBody;
    }
    catch (Exception ex)
    {
        File.AppendAllText(@"D:\API-LOAD-Tests\logs-api.txt", $"{DateTime.Now}: {ex.Message}{Environment.NewLine}");
        return null;
    }
}

方案一:使用SemaphoreSlim控制并发

var syntaxCommands = GetCommands();
var semaphore = new SemaphoreSlim(initialCount: 30); // 限制同时发起30个请求
var tasks = new List<Task<string>>();

foreach (var cmd in syntaxCommands)
{
    await semaphore.WaitAsync();
    tasks.Add(Task.Run(async () =>
    {
        try
        {
            return await _syntaxExecutor.Execute(cmd);
        }
        finally
        {
            semaphore.Release();
        }
    }));
}

var testResult = await Task.WhenAll(tasks);

方案二:使用Parallel.ForEachAsync(.NET 6+推荐)

var syntaxCommands = GetCommands();
var options = new ParallelOptions
{
    MaxDegreeOfParallelism = 30 // 控制并发数
};

var results = new List<string>();
await Parallel.ForEachAsync(syntaxCommands, options, async (cmd, token) =>
{
    var result = await _syntaxExecutor.Execute(cmd);
    lock (results) // 线程安全添加结果
    {
        results.Add(result);
    }
});

额外注意事项

  • 并发数不要设置过高,建议从20开始测试,逐步调整到目标API能承受的最大值。
  • 日志中添加时间戳,方便排查超时或错误的时间点。
  • 若目标API有速率限制,需根据限制调整并发数或添加重试机制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 18:20:06