【c#】队列(Queue)和MSMQ(消息队列)的基础使用
首先我们知道队列是先进先出的机制,所以在处理并发是个不错的选择。然后就写两个队列的简单应用。
Queue
命名空间
命名空间:System.Collections,不在这里做过多的理论解释,这个东西非常的好理解。
可以看下官方文档:https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.queue?view=netframework-4.7.2
示例代码
我这里就是为了方便记忆做了一个基本的例子,首先创建了QueueTest类:
包含了获取队列的数量,入队和出队的实现
public class QueueTest
{
public static Queue<string> q = new Queue<string>(); #region 获取队列数量
public int GetCount()
{ return q.Count;
}
#endregion #region 队列添加数据
public void IntoData(string qStr)
{
string threadId = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
q.Enqueue(qStr);
Console.WriteLine($"队列添加数据: {qStr};当前线程id:{threadId}");
}
#endregion #region 队列输出数据 public string OutData()
{
string threadId = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
string str = q.Dequeue();
Console.WriteLine($"队列输出数据: {str};当前线程id:{threadId}");
return str;
}
#endregion }
为了模拟并发情况下也不会出现重复读取和插入混乱的问题所以写了TaskTest类里面开辟了两个异步线程进行插入和读取:
这里只是证明了多线程插入不会造成丢失。无忧证明并发的先进先出
class TaskTest
{ #region 队列的操作模拟
public static void QueueMian()
{
QueueA();
QueueB();
}
private static async void QueueA()
{
QueueTest queue = new QueueTest();
var task = Task.Run(() =>
{
for (int i = ; i < ; i++)
{
queue.IntoData("QueueA" + i);
}
});
await task;
Console.WriteLine("QueueAA插入完成,进行输出:"); while (queue.GetCount() > )
{
queue.OutData();
}
} private static async void QueueB()
{
QueueTest queue = new QueueTest();
var task = Task.Run(() =>
{
for (int i = ; i < ; i++)
{
queue.IntoData("QueueB" + i);
}
});
await task;
Console.WriteLine("QueueB插入完成,进行输出:"); while (queue.GetCount() > )
{
queue.OutData();
}
}
#endregion }
效果展示
然后在main函数直接调用即可:

通过上面的截图可以看出插入线程是无先后的。

这张图也是线程无先后。
补充:通过园友的提问,我发现我一开始测试的不太仔细,只注意多线程下的插入,没有注意到输出其实不是跟插入的顺序一致,对不起,这说明queue不是线程安全的,所以这个就当是入队,出队的基础例子并不能说明并发。后面有一个补充的ConcurrentQueue队列是说明了并发线程的先进先出。
MSMQ
msmq是微软提供的消息队列,本来在windows系统中就存在,但是默认没有开启。需要开启。
开启安装
打开控制面板=>程序和功能=> 启动或关闭windows功能 => Microsoft Message Queue(MSMQ)服务器=>Microsoft Message Queue(MSMQ)服务器核心
一般选择:MSMQ Active Directory域服务继承和MSMQ HTTP支持即可。

点击确定等待安装成功。
命名空间
需要引用System.Messaging.DLL
命名空间:System.Messaging
官方资料文档:https://docs.microsoft.com/zh-cn/dotnet/api/system.messaging.messagequeue?view=netframework-4.7.2
示例代码
与上面queue同样的示例方式,创建一个MSMQ类,实现创建消息队列,查询数据,入列,出列功能:
/// <summary>
/// MSMQ消息队列
/// </summary>
class MSMQ
{
static string path = ".\\Private$\\myQueue";
static MessageQueue queue;
public static void Createqueue(string queuePath)
{
try
{
if (MessageQueue.Exists(queuePath))
{
Console.WriteLine("消息队列已经存在");
//获取这个消息队列
queue = new MessageQueue(queuePath);
}
else
{
//不存在,就创建一个新的,并获取这个消息队列对象
queue = MessageQueue.Create(queuePath);
path = queuePath;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
} } #region 获取消息队列的数量
public static int GetMessageCount()
{
try
{
if (queue != null)
{
int count = queue.GetAllMessages().Length;
Console.WriteLine($"消息队列数量:{count}");
return count;
}
else
{
return ;
}
}
catch (MessageQueueException e)
{ Console.WriteLine(e.Message);
return ;
} }
#endregion #region 发送消息到队列
public static void SendMessage(string qStr)
{
try
{
//连接到本地队列 MessageQueue myQueue = new MessageQueue(path); //MessageQueue myQueue = new MessageQueue("FormatName:Direct=TCP:192.168.12.79//Private$//myQueue1"); //MessageQueue rmQ = new MessageQueue("FormatName:Direct=TCP:121.0.0.1//private$//queue");--远程格式 Message myMessage = new Message(); myMessage.Body = qStr; myMessage.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); //发生消息到队列中 myQueue.Send(myMessage); string threadId = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
Console.WriteLine($"消息发送成功: {qStr};当前线程id:{threadId}");
}
catch (MessageQueueException e)
{
Console.WriteLine(e.Message);
}
}
#endregion #region 连接消息队列读取消息
public static void ReceiveMessage()
{
MessageQueue myQueue = new MessageQueue(path); myQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) }); try { //从队列中接收消息 Message myMessage = myQueue.Receive(new TimeSpan());// myQueue.Peek();--接收后不消息从队列中移除
myQueue.Close(); string context = myMessage.Body.ToString();
string threadId = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
Console.WriteLine($"--------------------------消息内容: {context};当前线程id:{threadId}"); } catch (System.Messaging.MessageQueueException e) { Console.WriteLine(e.Message); } catch (InvalidCastException e) { Console.WriteLine(e.Message); } }
#endregion
}
这里说明一下path这个字段,这是消息队列的文件位置和队列名称,我这里写的“.”(点)就是代表的位置MachineName字段,,代表本机的意思

然后TaskTest类修改成这个样子:
class TaskTest
{ #region 消息队列的操作模拟
public static void MSMQMian()
{
MSMQ.Createqueue(".\\Private$\\myQueue");
MSMQA();
MSMQB();
Console.WriteLine("MSMQ结束");
}
private static async void MSMQA()
{
var task = Task.Run(() =>
{
for (int i = ; i < ; i++)
{
MSMQ.SendMessage("MSMQA" + i);
}
});
await task;
Console.WriteLine("MSMQA发送完成,进行读取:"); while (MSMQ.GetMessageCount() > )
{
MSMQ.ReceiveMessage();
}
} private static async void MSMQB()
{
var task = Task.Run(() =>
{
for (int i = ; i < ; i++)
{
MSMQ.SendMessage("MSMQB" + i);
}
});
await task;
Console.WriteLine("MSMQB发送完成,进行读取:"); while (MSMQ.GetMessageCount() > )
{
MSMQ.ReceiveMessage();
}
}
#endregion
效果展示


本机查看消息队列
创建成功的消息队列我们可以在电脑上查看:我的电脑=>管理 =>计算机管理 =>服务与应用程序 =>消息队列 =>专用队列就看到我刚才创建的消息队列

补充感谢
感谢 virtual1988 提出的queue不是线程安全这个问题,是我没搞清楚。线程安全要使用ConcurrentQueue队列。
谢谢提出的宝贵意见。
ConcurrentQueue
所以我有修改了一下写了个ConcurrentQueue队列的:
修改代码如下:
//public static Queue<string> q = new Queue<string>();
public static ConcurrentQueue<string> q = new ConcurrentQueue<string>();
//public static Queue q =Queue.Synchronized(new Queue()); #region 获取队列数量
public static int GetCount()
{ return q.Count;
}
#endregion #region 队列添加数据
public static void IntoData(string qStr)
{
string threadId = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
q.Enqueue(qStr);
System.Threading.Thread.Sleep();
Console.WriteLine($"队列添加数据: {qStr};当前线程id:{threadId}");
}
#endregion #region 队列输出数据
public static string OutData2()
{
string threadId = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
foreach (var item in q)
{ Console.WriteLine($"------队列输出数据: {item};当前线程id:{threadId}");
string d="";
q.TryDequeue( out d);
} return "";
}
#endregion
task类:
#region 队列的操作模拟
public static async void QueueMian()
{
QueueA();
QueueB();
}
private static async void QueueA()
{
var task = Task.Run(() =>
{
for (int i = ; i < ; i++)
{
QueueTest.IntoData("QueueA" + i);
}
});
await task;
Console.WriteLine("QueueA插入完成,进行输出:");
} private static async void QueueB()
{
var task = Task.Run(() =>
{
for (int i = ; i < ; i++)
{
QueueTest.IntoData("QueueB" + i);
}
});
await task;
Console.WriteLine("QueueB插入完成,进行输出:"); } public static void QueueC()
{
Console.WriteLine("Queue插入完成,进行输出:");
while (QueueTest.GetCount() > )
{
QueueTest.OutData2();
}
}
#endregion
Main函数调用:
static void Main(string[] args)
{ try
{
Stopwatch stopWatch = new Stopwatch();
TaskTest.QueueMian();
Console.ReadLine();
TaskTest.QueueC();
Console.ReadLine();
}
catch (Exception e)
{ throw;
}
}
插入效果:

输出效果:

【c#】队列(Queue)和MSMQ(消息队列)的基础使用的更多相关文章
- WCF分布式开发必备知识(1):MSMQ消息队列
本章我们来了解下MSMQ的基本概念和开发过程.MSMQ全称MicroSoft Message Queue,微软消息队列,是在多个不同应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一 ...
- 跟我一起学WCF(1)——MSMQ消息队列
一.引言 Windows Communication Foundation(WCF)是Microsoft为构建面向服务的应用程序而提供的统一编程模型,该服务模型提供了支持松散耦合和版本管理的序列化功能 ...
- 【转】MSMQ消息队列安装
一.Windows 7安装.管理消息队列1.安装消息队列 执行用户必须要有本地 Administrators 组中的成员身份,或等效身份. 具体步骤: 开始—>控制面板—>程 ...
- MSMQ消息队列安装
一.Windows 7安装.管理消息队列1.安装消息队列 执行用户必须要有本地 Administrators 组中的成员身份,或等效身份. 具体步骤: 开始—>控制面板—>程 ...
- MSMQ消息队列
MSMQ全称MicroSoft Message Queue,微软消息队列,是在多个不同的应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一台机器上,也可以分布于相连的网络空间中的任一 ...
- 【6】.net msmq消息队列实例
1.msmq消息队列windows环境安装 控制面板---->程序和功能---->启用或关闭Windows程序---->Microsoft Message Queue(MSMQ)服务 ...
- WCF之MSMQ消息队列
一.MSMQ简介 MSMQ(微软消息队列)是Windows操作系统中消息应用程序的基础,是用于创建分布式.松散连接的消息通讯应用程序的开发工具. MSMQ与XML Web Services和.Net ...
- 微软MSMQ消息队列的使用
首先在windows系统中安装MSMQ 一.MSMQ交互 开发基于消息的应用程序从队列开始.MSMQ包含四种队列类型: 外发队列:消息发送到目的地之前,用它来临时存储消息. 公共队列:在主动目录中公布 ...
- C#实战Microsoft Messaging Queue(MSMQ)消息队列(干货)
前言 在使用MSMQ之前,我们需要自行安装消息队列组件!(具体安装方法大家自己搜一下吧) 采用MSMQ带来的好处是:由于是异步通信,无论是发送方还是接收方都不用等待对方返回成功消息,就可以执行余下的代 ...
- C#实战Microsoft Messaging Queue(MSMQ)消息队列
前言 在使用MSMQ之前,我们需要自行安装消息队列组件!(具体安装方法大家自己搜一下吧) 采用MSMQ带来的好处是:由于是异步通信,无论是发送方还是接收方都不用等待对方返回成功消息,就可以执行余下的代 ...
随机推荐
- docker 设计原理
自从上次更新博客截至目前已经8个多月之久,在这大半年里面,我自己经历了好多,换了工作,换了定位,从之前的小运维,到现在负责整个运维部的工作,需要自己协调的事情更多了,最大的成长是可以通过自己的见解对公 ...
- [LeetCode] Lemonade Change 买柠檬找零
At a lemonade stand, each lemonade costs $5. Customers are standing in a queue to buy from you, and ...
- verilog中timescale
1. `timescale `timescale是Verilog中的预编译指令,指定位于它后边的module的时间单位和时间精度,直到遇到新的`timescale指令或者`resetall指令.它的语 ...
- js-day01-js语言基础
JavaScript简介:JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本 ...
- React Native搭建开发环境 之 --走过的坑
React Native是使用JavaScript和React编写原生移动应用 我的开发平台是基于windows系统,所以只支持android,要是想开发ios系统,那就只能考虑使用沙盒环境 接下来就 ...
- Oracle:WITH AS () Merge ?
WITH AS 语法在SQL SERVER 和ORACLE数据库上均支持,主要用于子查询.语法如下: WITH expression_name [ ( column_name [,...n] ) ] ...
- Android OpenGL ES 开发(七): OpenGL ES 响应触摸事件
像旋转三角形一样,通过预设程序来让对象移动对于吸引注意是很有用的,但是如果你想让你的OpenGL图形有用户交互呢?让你的OpenGL ES应用有触摸交互的关键是,扩展你的GLSurfaceView的实 ...
- 非对称加密技术里面,最近出现了一种奇葩的密钥生成技术,iFace人脸密钥技术
要说到非对称加密技术啊,得先说说对称加密技术 什么是对称加密技术 对称加密采用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥加密. 也就是密钥也可以用作解密密钥,这种方法在密码学中叫做对称 ...
- postgresql 删除库的时候报错database "temp_test_yang" is being accessed by other users
删除库的时候报错 ERROR: database "temp_test_yang" is being accessed by other usersDETAIL: There ar ...
- Python——day11 函数(对象、名称空间、作用域、嵌套、闭包)
一.函数对象 函数名就是存放了函数的内存地址,存放了内存地址的变量都是对象,即 函数名 就是 函数对象 函数对象的应用 1. 可以直接被引用 fn = cp_fn 2 .可以当作函数参数传递 c ...