【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带来的好处是:由于是异步通信,无论是发送方还是接收方都不用等待对方返回成功消息,就可以执行余下的代 ...
随机推荐
- OJ002
register:这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中,而不是通过内存寻址访问,以提高效率.注意是尽可能,不是绝对. 因为,如果定义了很多register变量,可能会超过CPU的寄 ...
- Winsock编程基础2(Winsock编程流程)
1.套接字的创建和关闭 //创建套接字 SOCKET socket( int af, //指定套接字使用的地址格式,Winsock只支持AF_INET int type, //套接字类型 int pr ...
- async/await 的理解
1.如果一个方法标记了 async 关键字,那么这个方法被调用时就是异步执行: 2.利用Task运行一个任务,这个任务里的函数也是异步执行: 3.如果一个任务前被标记await,那么等待这个任务执行完 ...
- 干货分享: 长达250页的Libvirt Qemu KVM的ppt,不实验无真相
下载地址:Libvirt Qemu KVM 教程大全 http://files.cnblogs.com/popsuper1982/LibvirtQemuKVM.pptx 1. 概论 1.1 虚拟化的基 ...
- RabbitMQ in Action (1): Understanding messaging
1. Consumers and producers Producers create messages and publish (send) them to a broker server (Rab ...
- Cookie丢失的原因
最近在运行项目遇见cookie丢失的问题,这里简单总结了几点 1.Cookie的Domain设置不正确2.Cookie超时3.Cookie中含有一些非法字符,致使浏览器丢弃Cookie4.程序源码可能 ...
- 【DFS】求水洼的数目
题目: 有一个大小为 N*M 的园子,雨后积起了水.八连通的积水被认为是连接在一起的.请求出园子里总共有多少水洼?(八连通指的是下图中相对 W 的*的部分) *** *W* *** 限制条件:N, M ...
- Redis安装及使用详解
推荐在Linux系统上安装,这里我采用CentOS6: Redis采用3.0.0版本,官网下载即可 由于Redis是C语言编写,需要安装gcc(部分Linux自带gcc) yum install gc ...
- cmd命令窗口的快速选中复制黏贴
右击"窗口标题栏",选择属性,进入属性面板: 在"选项"面板勾选编辑选项下的"快速编辑模式"; 点击确认. 这时鼠标左键就有了选中功能,可以 ...
- mybatis框架(6)---mybatis插入数据后获取自增主键
mybatis插入数据后获取自增主键 首先理解这就话的意思:就是在往数据库表中插入一条数据的同时,返回该条数据在数据库表中的自增主键值. 有什么用呢,举个例子: 你编辑一条新闻,同时需要给该新闻打上标 ...