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

C#基于HttpListener的服务高并发请求处理性能优化求助

问题根因分析
  • 服务端核心处理逻辑同步阻塞:ProcessResponse方法中使用Thread.Sleep(2000)同步阻塞工作线程,单个请求会占用线程2秒,即使线程池满负载运行,处理能力也只能达到线程数/2 次/秒,远达不到数千级的性能要求。
  • 线程参数配置错误:HTTP_HANDLER_THREADS设置为5000完全无效,.NET线程池和操作系统都不会同时创建这么多线程,过多的线程只会带来额外的上下文切换开销,反而降低性能。该参数合理值为CPU核心数的2~4倍。
  • 请求处理流程存在多处同步IO:StreamReader.ReadToEnd()为同步读取方法,会阻塞线程等待IO完成,浪费线程资源。
  • 响应写入逻辑存在缺陷:OutputStream.WriteAsync()未等待异步操作完成就直接调用Close(),会导致部分响应数据丢失,请求失败率升高。
  • 压测代码逻辑存在问题:HttpClient.PostAsync是异步方法,代码未添加await等待请求完成就统计发送数,计数完全失真;Parallel.For默认并发度有限,且HttpClient默认的最大连接数限制会导致大量请求排队,无法真实模拟高并发场景。
优化方案

服务端优化

  1. 全异步改造处理流程:将同步阻塞逻辑全部替换为异步实现,Thread.Sleep改为await Task.Delay,同时将请求读取、处理、响应写入全链路改为异步,避免阻塞工作线程。
  2. 调整线程池参数:将HTTP_HANDLER_THREADS调整为CPU核心数的24倍(例如8核CPU设置为1632),无需设置过大。
  3. 修正响应写入逻辑:等待异步写入完成后再关闭输出流,避免数据丢失。

优化后的核心代码示例:

// 首先将ProcessDataDelegate改为异步委托
public delegate Task<byte[]> ProcessDataDelegate(string request);

// 改造ProcessRequestHandler为异步
private async void ProcessRequestHandler(Task<HttpListenerContext> result)
{
    var context = result.Result;
    if (!listener.IsListening) return;

    // 提前启动下一个上下文监听
    listener.GetContextAsync().ContinueWith(ProcessRequestHandler);

    try
    {
        // 异步读取请求
        using var reader = new StreamReader(context.Request.InputStream);
        var request = await reader.ReadToEndAsync();

        // 异步执行业务处理
        var response_bytes = await handler.Invoke(request);
        context.Response.ContentLength64 = response_bytes.Length;

        // 异步写入响应并等待完成
        using var output = context.Response.OutputStream;
        await output.WriteAsync(response_bytes, 0, response_bytes.Length);
    }
    catch (Exception ex)
    {
        // 可添加异常处理逻辑
        context.Response.StatusCode = 500;
    }
    finally
    {
        context.Response.Close();
    }
}

// 改造ProcessResponse为异步方法
private static async Task<byte[]> ProcessResponse(string response)
{
    // 线程安全累加计数
    Interlocked.Increment(ref request_amount);
    Console.WriteLine(request_amount);
    
    // 异步等待模拟业务耗时,不阻塞线程
    await Task.Delay(2000);
    return Array.Empty<byte>();
}

压测端优化

  1. 修正异步调用逻辑:添加await等待PostAsync执行完成,保证统计准确。
  2. 解除HttpClient连接限制:启动时设置ServicePointManager.DefaultConnectionLimit = 1024,解除默认的2连接/域名的限制。
  3. 采用合理的并发控制:可使用信号量SemaphoreSlim限制并发数,避免瞬间请求量过大压垮测试端。

优化后的压测代码示例:

class Program
{
    private static readonly HttpClient client = new HttpClient();
    private const int send_amount = 200000;
    private static int sent_request = 0;
    // 控制并发数为1000,可根据实际情况调整
    private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(1000);

    static async Task Main(string[] args)
    {
        // 解除连接限制
        ServicePointManager.DefaultConnectionLimit = 1024;
        var tasks = new List<Task>();

        for (int i = 0; i < send_amount; i++)
        {
            await semaphore.WaitAsync();
            tasks.Add(SendRequestAsync(i));
        }

        await Task.WhenAll(tasks);
        Console.WriteLine("所有请求发送完成");
    }

    private static async Task SendRequestAsync(int index)
    {
        try
        {
            var values = new Dictionary<string, string>
            {
                { "request", index.ToString() }
            };
            var content = new FormUrlEncodedContent(values);
            var response = await client.PostAsync("http://192.168.102.165:1990", content);
            response.EnsureSuccessStatusCode();
            Interlocked.Increment(ref sent_request);
            Console.WriteLine($"Sent request {sent_request}/{send_amount}");
        }
        finally
        {
            semaphore.Release();
        }
    }
}

按照以上方案优化后,服务端即可达到每秒数千次的请求处理能力。如果业务处理逻辑本身无耗时,可将Task.Delay移除,性能会进一步提升。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 10:21:02