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

如何在C#异步控制台应用中异步运行带回调的WebSocket任务?

解决异步控制台应用中WebSocket回调不阻塞主逻辑的问题

我来帮你搞定这个问题!你的核心需求是让Binance WebSocket的订阅逻辑不阻塞MainAsync里的后续代码,对吧?咱们可以把WebSocket的逻辑包装成异步任务,同时用取消令牌来优雅地控制它的生命周期,完美适配你的异步控制台架构。

整合后的完整代码示例

using Nito.AsyncEx;
using ExchangeSharp;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        // 用AsyncContext托管异步主逻辑,解决控制台应用的异步入口问题
        AsyncContext.Run(() => MainAsync());
    }

    static async Task MainAsync()
    {
        // 创建取消令牌源,用来统一控制WebSocket的生命周期
        using var cts = new CancellationTokenSource();

        // 启动WebSocket异步任务,这一步不会阻塞MainAsync的执行
        var webSocketTask = RunBinanceTickersWebSocketAsync(cts.Token);

        // 🚀 这里可以放心写MainAsync后续的业务逻辑了,完全不会被WebSocket阻塞
        Console.WriteLine("MainAsync正在执行其他异步逻辑...");
        await Task.Delay(3000); // 模拟你的业务操作,比如请求其他API、处理数据等
        Console.WriteLine("MainAsync的前置逻辑执行完毕,准备关闭WebSocket连接");

        // 发送取消信号,通知WebSocket任务结束
        cts.Cancel();
        // 等待WebSocket任务完全清理资源后再继续
        await webSocketTask;

        Console.WriteLine("程序正常退出");
    }

    static async Task RunBinanceTickersWebSocketAsync(CancellationToken cancellationToken)
    {
        var binanceApi = new ExchangeBinanceAPI();
        
        // 使用using确保WebSocket连接在任务结束时被正确释放
        using var tickerSocket = binanceApi.GetTickersWebSocket((tickers) =>
        {
            // 回调逻辑保持不变,收到tickers时打印信息
            Console.WriteLine("{0} tickers received, first one: {1}", tickers.Count, tickers.First());
        });

        Console.WriteLine("Binance WebSocket已启动,按任意键可提前关闭;或等待MainAsync自动触发关闭");

        // 把阻塞的Console.ReadKey包装成异步任务,同时绑定取消令牌
        var userInputTask = Task.Run(() => Console.ReadKey(), cancellationToken);

        try
        {
            // 等待两个事件中的任意一个:用户按键 或 收到取消信号
            await Task.WhenAny(userInputTask, Task.Delay(Timeout.Infinite, cancellationToken));
        }
        catch (OperationCanceledException)
        {
            // 捕获取消异常,这是正常的终止流程,不需要报错
            Console.WriteLine("WebSocket收到终止信号,正在断开连接...");
        }
    }
}

关键细节解释

  • 取消令牌(CancellationToken):这是异步编程中优雅终止任务的标准方式,避免资源泄漏。当MainAsync完成前置逻辑后,调用cts.Cancel()就能通知WebSocket任务安全关闭。
  • 异步化用户输入:原来的Console.ReadLine()是同步阻塞方法,会卡住整个线程。我们用Task.Run把它包装成异步任务,同时绑定取消令牌,这样既能响应用户手动关闭,又能在收到取消信号时立即终止。
  • 非阻塞启动WebSocket:通过var webSocketTask = RunBinanceTickersWebSocketAsync(cts.Token)启动任务后,MainAsync会立刻继续执行后续代码,不会等待WebSocket任务结束,完全满足你的需求。
  • 资源安全释放:using语句会自动处理WebSocket的Dispose操作,不管是用户手动关闭还是取消信号触发,都能保证连接被正确断开。

额外提示

  • 如果不需要用户手动关闭WebSocket,可以去掉userInputTask相关代码,只保留await Task.Delay(Timeout.Infinite, cancellationToken),这样WebSocket会完全由MainAsync的取消令牌控制。
  • 如果你需要在MainAsync中随时和WebSocket回调交互,可以考虑用线程安全的队列或者变量传递数据,避免多线程冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:41:42