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

如何用async/await优化.NET Core控制台应用多WebSocket读取效率?

优化多WebSocket异步读取的实现方案

这问题我熟,之前帮不少人优化过类似的WebSocket读取场景,你的思路完全对——async/await就是解决这种阻塞I/O低效问题的利器,咱们一步步来改:

首先得说清为啥你原来的方式效率低:用Task.Run套阻塞循环,每个WebSocket都会占一个线程池线程,而且大部分时间都卡在阻塞等待数据上,线程根本没在干活,纯浪费资源。而async/await的核心就是在I/O等待时释放线程,让线程去处理其他任务,等数据来了再回来继续执行,完美匹配你这种低频率推送的场景。

下面是具体的实现思路和代码示例:

1. 把每个WebSocket的读取逻辑改成异步方法

WebSocket的ReceiveAsync本身就是异步方法,完全不需要用阻塞的方式读取。咱们写一个专门的异步循环方法来处理单个WebSocket的持续读取:

private static async Task ProcessWebSocketAsync(WebSocket webSocket, CancellationToken cancellationToken)
{
    var buffer = new byte[1024 * 4];
    try
    {
        while (!cancellationToken.IsCancellationRequested && webSocket.State == WebSocketState.Open)
        {
            // 异步等待数据,这里不会阻塞线程
            var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken);
            
            if (result.MessageType == WebSocketMessageType.Close)
            {
                await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken);
                break;
            }

            // 处理读取到的数据,比如解析、存储等
            var receivedData = new byte[result.Count];
            Array.Copy(buffer, receivedData, result.Count);
            Console.WriteLine($"Received data from WebSocket: {Encoding.UTF8.GetString(receivedData)}");
        }
    }
    catch (OperationCanceledException)
    {
        // 处理取消请求
        await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Cancellation requested", cancellationToken);
    }
    catch (Exception ex)
    {
        // 处理其他异常,比如连接断开
        Console.WriteLine($"WebSocket error: {ex.Message}");
        if (webSocket.State == WebSocketState.Open)
        {
            await webSocket.CloseAsync(WebSocketCloseStatus.InternalServerError, ex.Message, cancellationToken);
        }
    }
    finally
    {
        webSocket.Dispose();
    }
}

2. 批量启动所有WebSocket的异步任务

在主程序里,你只需要创建每个WebSocket连接,然后调用上面的异步方法,把所有任务收集起来,用Task.WhenAll等待它们完成(或者根据需求管理这些任务):

static async Task Main(string[] args)
{
    var cancellationTokenSource = new CancellationTokenSource();
    // 假设你有多个WebSocket的地址列表
    var webSocketUrls = new List<string> { "wss://example.com/ws1", "wss://example.com/ws2", "wss://example.com/ws3" };
    
    // 收集所有WebSocket的处理任务
    var webSocketTasks = new List<Task>();
    foreach (var url in webSocketUrls)
    {
        try
        {
            var client = new ClientWebSocket();
            await client.ConnectAsync(new Uri(url), cancellationTokenSource.Token);
            Console.WriteLine($"Connected to {url}");
            
            // 启动异步读取任务,不需要Task.Run!因为ProcessWebSocketAsync本身就是异步的
            webSocketTasks.Add(ProcessWebSocketAsync(client, cancellationTokenSource.Token));
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Failed to connect to {url}: {ex.Message}");
        }
    }

    // 等待所有任务完成(或者你可以在这里处理程序退出逻辑,比如监听控制台输入来取消)
    Console.WriteLine("Press any key to exit...");
    Console.ReadKey();
    cancellationTokenSource.Cancel();
    
    try
    {
        await Task.WhenAll(webSocketTasks);
    }
    catch (AggregateException ex)
    {
        foreach (var innerEx in ex.InnerExceptions)
        {
            Console.WriteLine($"Task error: {innerEx.Message}");
        }
    }
}

3. 关键优化点说明

  • 不要用Task.Run包装异步方法:ProcessWebSocketAsync本身就是异步的,调用它会直接返回一个Task,不需要额外用Task.Run去开线程,那样反而多此一举,浪费线程池资源。
  • 用CancellationToken管理取消:方便统一关闭所有WebSocket连接和终止任务,避免程序退出时出现资源泄漏。
  • 异常处理要到位:WebSocket连接可能随时断开,要在异步方法里捕获异常并正确关闭连接,释放资源。

这样改完之后,线程池里的线程不会被闲置阻塞,每个I/O等待都会释放线程去处理其他工作,效率会提升很多,完全适配你这种低频率数据推送的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:01:26