【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带来的好处是:由于是异步通信,无论是发送方还是接收方都不用等待对方返回成功消息,就可以执行余下的代 ...
随机推荐
- 口袋appnabcd
N(need)需求:依据我们学习经历的情况而言,对于初次接触的专业的学生来说,对学习的方向上会感到迷茫,不知道如何学习以及不知道学什么.比如对于计算机专业来说,对于一些软件的选择和下载,应用环境配置等 ...
- MVCAPi Httpclient
APi配制文件 删除修改api 显示和命名空间 新增
- RTN 实操
创建房间 test-rtn 10001 e2uii6r7r 8LfwOcreM76OiV1V1y8jXrMG_BNa-cmktpWUznRa:kdYdsEpcYLc5ceWEHPaK0ZDI7Qc=: ...
- mysql中Table is read only的解决方法
首先去到mysq的bin目录 cd /usr/local/mysql/bin 执行如下mysqladmin ./mysqladmin -p flush-tables 接着输入数据库存的root密码即可
- 让MEF插上AOP的翅膀
什么是MEF Git:https://github.com/MicrosoftArchive/mef MEF也是一款ioc框架,貌似历史比较悠久了. 这里有一篇.net阵容里面主流ioc比较. htt ...
- Ubuntu 16.04下安装搜狗输入法
在确保更新了国内镜像源的前提下: 安装sogou输入法步骤 一.安装fcitx键盘输入法系统(系统已安装的可忽略此步骤) 1.添加以下源 sudo add-apt-repository ppa:fci ...
- 全面盘点当前Android后台保活方案的真实运行效果(截止2019年前)
本文原作者“minminaya”,作者网站:minminaya.cn,为了提升文章品质,即时通讯网对内容作了幅修订和改动,感谢原作者. 1.引言 对于IM应用和消息推送服务的开发者来说,在Androi ...
- [Swift]LeetCode976. 三角形的最大周长 | Largest Perimeter Triangle
Given an array A of positive lengths, return the largest perimeter of a triangle with non-zero area, ...
- Spotlight监控Oracle--Spotlight On Oracle安装和使用
网上找了很久,发现单独Spotlight On Oracle的安装包很少,要么要积分C币的,要么官网要授权的. 应用过程中也没有一个集安装与运用与一体的文档,故汇总相关信息,供参考. Spotligh ...
- java 随机数产生 常用类及方法
1.Random类 Random():创建一个新的随机数生成器. new一个Random类的对象: Random r = new Random(); 利用该对象产生一个随机整数:常用nextInt,不 ...