news 2026/6/25 5:36:18

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/6/24 22:42:06

快速验证:用Anaconda搭建Python开发环境

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 设计一个快速安装Anaconda的脚本&#xff0c;支持最小化安装和常用库的预配置。脚本应能在5分钟内完成安装并启动Jupyter Notebook&#xff0c;适合快速验证项目原型。使用AI优化安…

作者头像 李华
网站建设 2026/6/13 19:15:52

洛雪音乐源在实际项目中的集成与应用案例

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个示例项目&#xff0c;演示如何将洛雪音乐源集成到Python音乐播放器中。功能要求&#xff1a;1. 从洛雪音乐源获取歌曲列表&#xff1b;2. 实现基本的播放控制&#xff08;…

作者头像 李华
网站建设 2026/6/18 0:41:08

3分钟搞定!MSVCR120.DLL丢失的高效修复流程

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个极简DLL修复工具&#xff0c;核心功能&#xff1a;1. 极速扫描(3秒内完成) 2. 一键修复(自动选择最优方案) 3. 静默安装模式 4. 修复历史记录。要求使用C#开发&#xff0c…

作者头像 李华
网站建设 2026/6/14 18:36:43

AI如何帮你一键查询硬盘序列号?告别复杂CMD命令

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个智能硬盘信息查询工具&#xff0c;要求&#xff1a;1. 支持通过自然语言输入查询需求&#xff08;如帮我查C盘序列号&#xff09;2. 自动生成对应的CMD/PowerShell命令 3.…

作者头像 李华
网站建设 2026/6/14 8:19:14

VibeThinker-1.5B数学能力边界:哪些难题仍无法解决?

VibeThinker-1.5B数学能力边界&#xff1a;哪些难题仍无法解决&#xff1f; 1. 引言 随着大模型技术的快速发展&#xff0c;小型语言模型在特定任务上的表现逐渐引起关注。VibeThinker-1.5B 是微博开源的一款仅含15亿参数的密集型语言模型&#xff0c;其训练成本控制在7,800美…

作者头像 李华
网站建设 2026/6/16 11:09:54

企业级应用中解决‘方法不存在‘错误的5个真实案例

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个案例展示应用&#xff0c;包含5个典型的企业应用场景中出现的方法不存在错误案例&#xff1a;1. Spring Boot中接口版本升级导致的方法签名变更&#xff1b;2. .NET Core中…

作者头像 李华