基于C# SignalR实现每5秒打印队列成员数的技术求助
解决方案
核心思路是将队列从Hub内部剥离到独立的单例服务中,确保所有Hub实例共享同一队列,再通过后台定时任务实现周期性打印队列数量。
1. 创建独立队列管理服务
创建单例服务封装队列操作,保证全局唯一实例,同时处理线程安全:
public class QueueManager { private readonly Queue<QueueItem> _queue = new Queue<QueueItem>(); private readonly object _lockObj = new object(); // 添加成员到队列 public void Enqueue(QueueItem item) { lock (_lockObj) { _queue.Enqueue(item); } } // 获取当前队列成员数量 public int GetQueueCount() { lock (_lockObj) { return _queue.Count; } } }
2. 注册单例服务
在Program.cs中注册该服务为单例,确保全局共享:
builder.Services.AddSingleton<QueueManager>();
3. 修改SignalR Hub
注入QueueManager,替换原有私有队列逻辑:
public class QueueHub : Hub { private readonly QueueManager _queueManager; public QueueHub(QueueManager queueManager) { _queueManager = queueManager; } public async Task JoinQueue(QueueItem item) { _queueManager.Enqueue(item); // 可追加客户端通知逻辑 await Clients.All.SendAsync("QueueUpdated", _queueManager.GetQueueCount()); } }
4. 实现后台定时打印服务
创建继承自BackgroundService的后台服务,每5秒打印队列数量:
public class QueueCountPrinter : BackgroundService { private readonly QueueManager _queueManager; public QueueCountPrinter(QueueManager queueManager) { _queueManager = queueManager; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { int count = _queueManager.GetQueueCount(); Console.WriteLine($"当前队列成员数量:{count}"); await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken); } } }
在Program.cs中注册该后台服务:
builder.Services.AddHostedService<QueueCountPrinter>();
关键说明
- 线程安全:队列操作加锁,避免多线程并发访问时的异常。
- 单例模式:解决Hub瞬时性导致的队列无法跨实例共享问题。
- 后台服务:依托ASP.NET Core标准后台任务机制,自动随应用生命周期启停。
内容的提问来源于stack exchange,提问作者Crisiroid
相关产品推荐
相关产品推荐

