news 2026/3/29 11:21:46

C#高级:使用ConcurrentQueue做一个简易进程内通信的消息队列

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#高级:使用ConcurrentQueue做一个简易进程内通信的消息队列

文章目录

  • 一、简介
  • 二、使用场景
  • 三、好处
  • 四、代码
  • 总结

一、简介

使用ConcurrentQueue实现线程安全的进程内消息队列,支持多生产者/消费者模式。

二、使用场景

多线程间数据交换、异步任务处理、日志缓冲等需要线程安全队列的场景。

三、好处

  • 线程安全:内置锁机制,无需额外同步
  • 高性能:无锁设计减少竞争
  • 易用性强:实例绑定Key,简化队列管理

四、代码

usingSystem;usingSystem.Collections.Concurrent;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Threading;usingSystem.Threading.Tasks;/// <summary>/// 简易队列管理器(实例绑定唯一Key,无需重复传参)/// </summary>/// <typeparam name="T">队列元素类型</typeparam>publicclassEasyQueue<T>:IDisposable{// 静态字典:全局管理所有Key对应的队列(保证Key唯一)privatestaticreadonlyConcurrentDictionary<string,ConcurrentQueue<T>>_globalQueueDict=new();// 实例专属Key(创建实例时指定,后续操作无需传参)publicstringQueueKey{get;}// 实例绑定的队列(避免每次从全局字典获取)privateConcurrentQueue<T>_boundQueue;/// <summary>/// 构造函数:注册Key并绑定专属队列(核心优化点)/// </summary>/// <param name="queueKey">队列唯一标识(注册Key)</param>/// <exception cref="ArgumentNullException">Key为空时抛出</exception>publicEasyQueue(stringqueueKey){if(string.IsNullOrWhiteSpace(queueKey))thrownewArgumentNullException(nameof(queueKey),"队列Key不能为空或空白");QueueKey=queueKey;// 注册Key:不存在则创建新队列,存在则绑定已有队列(线程安全)_boundQueue=_globalQueueDict.GetOrAdd(queueKey,_=>newConcurrentQueue<T>());}#region核心方法(无需传Key,直接操作实例绑定的队列)/// <summary>/// 单个元素入队(实例方法,无需传Key)/// </summary>/// <param name="item">要入队的元素</param>publicvoidEnqueue(Titem){_boundQueue.Enqueue(item);}/// <summary>/// 批量元素入队(实例方法,无需传Key)/// </summary>/// <param name="items">要入队的元素列表</param>/// <exception cref="ArgumentNullException">列表为空时抛出</exception>publicvoidEnqueue(List<T>items){if(items==null||items.Count==0)thrownewArgumentNullException(nameof(items),"入队元素列表不能为空或空列表");foreach(variteminitems){_boundQueue.Enqueue(item);}}/// <summary>/// 出队(实例方法,无需传Key)/// </summary>/// <param name="item">出队的元素(队列为空时返回default(T))</param>/// <returns>是否出队成功(true=成功,false=队列为空)</returns>publicboolDequeue(outTitem){return_boundQueue.TryDequeue(outitem);}/// <summary>/// 查询队列所有元素(实例方法,无需传Key)/// </summary>/// <returns>队列元素列表(队列为空返回空List)</returns>publicList<T>GetQueueItems(){return_boundQueue.ToList();}#endregion#region扩展实用方法(实例级,无需传Key)/// <summary>/// 判断当前实例绑定的队列是否为空/// </summary>publicboolIsEmpty=>_boundQueue.IsEmpty;/// <summary>/// 获取当前队列的元素数量/// </summary>publicintCount=>_boundQueue.Count;/// <summary>/// 清空当前队列/// </summary>publicvoidClear(){while(_boundQueue.TryDequeue(out_)){}}/// <summary>/// 静态方法:移除全局字典中的指定Key(注销队列)/// </summary>/// <param name="queueKey">要注销的Key</param>/// <returns>是否注销成功</returns>publicstaticboolUnregisterQueue(stringqueueKey){if(string.IsNullOrWhiteSpace(queueKey))thrownewArgumentNullException(nameof(queueKey));return_globalQueueDict.TryRemove(queueKey,out_);}/// <summary>/// 静态方法:查询全局已注册的所有队列Key/// </summary>/// <returns>所有Key的列表</returns>publicstaticList<string>GetAllRegisteredKeys(){return_globalQueueDict.Keys.ToList();}#endregion#region资源释放privatebool_disposed=false;protectedvirtualvoidDispose(booldisposing){if(!_disposed){if(disposing){// 释放实例时清空绑定的队列(可选,根据业务需求调整)Clear();}_disposed=true;}}publicvoidDispose(){Dispose(true);GC.SuppressFinalize(this);}#endregion}classProgram{staticvoidMain(string[]args){// 定义队列KeyconststringtestKey="MultiThreadQueue";// ========== 线程1:生产数据(入队) ==========TaskproduceTask=Task.Run(()=>{// 创建生产端实例(绑定testKey)varproducerQueue=newEasyQueue<int>(testKey);for(inti=1;i<=100;i++){producerQueue.Enqueue(i);Console.WriteLine($"【生产线程】入队:{i}");Thread.Sleep(1000);// 模拟生产耗时}Console.WriteLine("【生产线程】生产完成!");});// ========== 线程2:消费数据(出队) ==========TaskconsumeTask=Task.Run(()=>{// 创建消费端实例(绑定同一个testKey)varconsumerQueue=newEasyQueue<int>(testKey);intconsumeCount=0;// 循环消费,直到生产完成且队列为空while(!produceTask.IsCompleted||!consumerQueue.IsEmpty){if(consumerQueue.Dequeue(outintitem)){consumeCount++;Console.WriteLine($"【消费线程】出队:{item}");}else{Thread.Sleep(5);// 队列为空时短暂等待,避免空轮询}}Console.WriteLine($"【消费线程】消费完成!共消费{consumeCount}个元素");});// 等待所有线程完成Task.WaitAll(produceTask,consumeTask);Console.WriteLine("\n所有操作完成!");}}

总结

通过ConcurrentQueue和ConcurrentDictionary实现了一个线程安全的进程内消息队列。该方案支持Key绑定机制简化队列管理,提供完整的生产消费示例,适用于多线程数据交换场景,具备高性能和易用性特点。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/22 13:59:00

AI如何帮你解决MSCOMCTL.OCX兼容性问题

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个Windows兼容性修复工具&#xff0c;主要功能&#xff1a;1. 自动检测系统是否缺少MSCOMCTL.OCX组件 2. 提供一键下载和注册该组件的功能 3. 对于无法注册的情况&#xff0…

作者头像 李华
网站建设 2026/3/26 23:19:14

告别手动调试:NGINX配置AI生成+自动测试工作流

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 生成一个对比报告&#xff1a;1. 传统方式下配置NGINX反向代理的步骤和时间估算&#xff1b;2. 使用快马平台AI生成的步骤和时间对比&#xff1b;3. 重点展示nginx -T测试命令在不…

作者头像 李华
网站建设 2026/3/25 13:35:36

零基础学Docker:第一个镜像的创建与运行

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 为完全不懂Docker的新手创建一个入门教程镜像&#xff0c;要求&#xff1a;1) 基于官方nginx镜像 2) 替换默认首页为显示Hello Docker!的简单HTML页面 3) 暴露80端口 4) 包含详细的…

作者头像 李华
网站建设 2026/3/23 22:17:40

告别繁琐!3种高效获取Postman旧版本的技巧

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个多功能Postman版本获取工具&#xff0c;集成三种获取方式&#xff1a;1)命令行交互工具 2)浏览器扩展插件 3)REST API服务。核心功能包括版本列表展示、条件筛选、下载加速…

作者头像 李华
网站建设 2026/3/25 8:20:17

用555488在10分钟内构建可运行产品原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 基于555488快速生成一个可演示的产品原型&#xff0c;要求&#xff1a;1. 识别555488作为产品核心参数&#xff1b;2. 实现一个简单的Web应用展示其功能&#xff08;如数字转换器、…

作者头像 李华
网站建设 2026/3/20 1:57:31

零基础玩转VLA:5分钟搭建你的第一个视觉语言应用

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个极简VLA体验页面。功能&#xff1a;1) 拖拽上传图片 2) 显示AI生成的3种描述版本 3) 基础编辑功能 4) 分享按钮。使用预设的简单模型&#xff0c;界面要有引导提示和示例图…

作者头像 李华