本文版权归博客园和作者吴双本人共同所有。欢迎转载,转载和爬虫请注明原文地址:http://www.cnblogs.com/tdws/p/5860668.html

想必MQ这两个字母对于各位前辈们和老司机们并不陌生。本文初探RabbitMQ的简单分享可能值得学习之处不怎么多,本人对于RabbitMQ的研究目前也很初级,这个月打算按照好的学习线路提高一下,欢迎新老司机留下你们的见解。

首先提到第一个简单的场景,文件并发。我先手动实现一下文件并发,引发异常,请看如下代码。

 static void Main(string[] args)
{
new Thread(write1).Start();
new Thread(write1).Start();
new Thread(write1).Start();
Console.WriteLine("等待");
Console.ReadKey();
}
public static void write1()
{
for (int i = ; i < ; i++)
{
WriteLog(i);
}
//Console.ReadKey();
}
public static void WriteLog(int i)
{
using (FileStream f = new FileStream(@"d:\\A.txt", FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(f, Encoding.Default))
{
sw.Write(i);
}
}
}

我使用多线程并发向同一个append数据。相信你应该知道接下来运行起来会发生什么!

是的,正如你所料,该文件正由另一个进程使用,因此该进程无法访问此文件。也许这个场景,就像你写应用程序运行日志,异常日志。如果你没使用任何插件或者组件,就只能直接向文件中append。这样的问题,是你不得不解决的。

这个时候就是队列出场的时候了。当然队列的组件有很多,.NET框架下也有自带的队列Queue,微软也有独立的队列组件MSQueue。Apache有其ActiveMQ,另外知名的消息队列还有Equeue,ZeroMQ等。消息队列的使用场景,大概包括解耦,提高峰值处理能力,送达和排序保证,缓冲等。

RabbitMQ是一个消息中间件,其主要的观点很简单:接受和转发消息。你可以把他想象成邮局,当你发送新建到邮递箱,你很确定邮递员最终将会把你的新建传递到你的收件人手中。我们使用邮递箱和邮递员来隐喻RabbitMQ。关于RabbitMQ和邮局之前的主要区别在于邮局处理纸质信件,而MQ存储和转发二进制数据-message。下面提到RabbitMQ的几个”行话“。

生产者意味着发送消息。一个发送消息的应用程序是一个生产者,我们称其为"P"。

队列queue意味着邮递箱。他存在于RabbitMQ当中.尽管消息在RabbitMQ和你的应用程序中”流通“,他们可以被仅存在一个队列当中。一个队列不受任何限制,他可以存储你想要存储的消息量,它本质上是一个无限的缓冲区。多个生产者可以向同一个队列发送消息,多个消费者可以尝试从同一个消息队列中接收数据。一个队列像下面这样,上面是它的队列名称。

消费者意味着接收,消费者是等待接收处理消息的应用程序。

最后的关系就如下图:

接下来,我将使用RabbitMQ来解决最开始的文件并发问题。也就是说为了避免文件并发,我们要将生产者所需append到文件中的内容存入到消息队列当中,然后取出队列中的message让消费者写入到文件当中。关于RabbitMQ的安装和配置请先看张善友老师的文章:http://www.cnblogs.com/shanyou/p/4067250.html ,写的特别详细。只不过历经数月RabbitMQ C#客户端方法上有略微的更新。

下面我将新建两个ConsoleApp应用程序。一个负责Receive,消费者,写文件。另一个Send,生产者,将所需写入的数据推到RabbitMQ当中。

Receive代码如下:

 static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "127.0.0.1", UserName = "WuShuang", Password = "" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null); var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
WriteLog(message);
};
channel.BasicConsume(queue: "hello",
noAck: true,
consumer: consumer); Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
public static void WriteLog(string i)
{
using (FileStream f = new FileStream(@"d:\\A.txt", FileMode.Append))
{
using (StreamWriter sw = new StreamWriter(f, Encoding.Default))
{
sw.Write(i + "\n");
}
}
}

Send代码如下:

static void Main(string[] args)
{
new Thread(write1).Start();
new Thread(write1).Start();
new Thread(write1).Start();
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
} public static void write1()
{
var factory = new ConnectionFactory() { HostName = "127.0.0.1", UserName = "WuShuang", Password = "" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello", durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
channel.QueueBind("hello", "wsExchange", "hello");
for (int i = ; i < ; i++)
{
string message = "Hello World ws!" + i;
var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "wsExchange",
routingKey: "hello",
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
}
} //Console.ReadKey();
}

有了代码后,首先把Receive项目运行起来。等待生产者Send消息到队列中,然后Receive订阅的事件将会取出消息,并将消息写入到文件当中。

左侧的ConsoleApp持续向队列中写入消息,右侧的Receive的ConsoleApp运行过程中,会不断写文件。生产者承受了多线程并发些数据,当然消费者有序的取出队列中的数据,也不会发生最开始的文件并发异常。

今天的分享就这么简单,关于RabbitMQ有待继续深入学习。

如果您觉得我的点滴分享,对您有点滴帮助,欢迎点赞,也为您自己的进步点赞!

点击下方关注,我们共同进步!

分享的过程中,总会遇到不断地惊喜。

参考文章:

张善友老师:Windows上安装RabbitMQ指南

RabbitMQ(开源)官方文档 Hello world

.NET文件并发与RabbitMQ(初探RabbitMQ)的更多相关文章

  1. RabbitMq初探——安装

    rabbitmq Server安装 rabbitmq server安装很简单. 安装erlang环境 rpm -ihv erlang-18.1-1.el6.x86_64.rpm rpm -ihv ra ...

  2. RabbitMq初探——消息均发

    消息均发 前言 由前文 RabbitMq初探——消息分发 可知,rabbitmq自带分发机制——消息会按顺序的投放到该队列下的多个消费者,例如1,3,5投放消费者C1,2,4,6投放消费者C2. 这就 ...

  3. Java秒杀实战 (六) 服务级高并发秒杀优化(RabbitMQ+接口优化)

    转自:https://blog.csdn.net/qq_41305266/article/details/81146716 一.思路:减少数据库访问 1.系统初始化,把商品库存数量加载到Redis 2 ...

  4. 我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比(转载)

    转载自:https://www.sojson.com/blog/48.html 前言: MQ 是什么?队列是什么,MQ 我们可以理解为消息队列,队列我们可以理解为管道.以管道的方式做消息传递. 场景: ...

  5. 【RabbitMQ】 RabbitMQ配置开机启动

    环境 系统:Linux(CentOS 7.2) Erlang环境:21.1(安装参考[Erlang]源码安装) RabbitMQ:3.7.9(安装参考[RabbitMQ] RabbitMQ安装) 配置 ...

  6. 为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比

    原文:https://www.sojson.com/blog/48.html 前言: MQ 是什么?队列是什么,MQ 我们可以理解为消息队列,队列我们可以理解为管道.以管道的方式做消息传递. 场景: ...

  7. 快速掌握RabbitMQ(一)——RabbitMQ的基本概念、安装和C#驱动

    1 RabbitMQ简介 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现,官网地址:http://www.rabbitmq.com.Ra ...

  8. 【详细】【转】C#中理解委托和事件 事件的本质其实就是委托 RabbitMQ英汉互翼(一),RabbitMQ, RabbitMQ教程, RabbitMQ入门

    [详细][转]C#中理解委托和事件   文章是很基础,但很实用,看了这篇文章,让我一下回到了2016年刚刚学委托的时候,故转之! 1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托 ...

  9. 【RabbitMQ】RabbitMQ的一些基础概念

    工作中使用的是RabbitMQ,需要对其进行熟悉.使用之前,弄清楚它是什么东西,解决什么问题. 场景 一些不必实时执行的任务 开发中,有一些任务并无须实时执行,比如: 会员更新个人信息,更新会员信息之 ...

随机推荐

  1. [.NET] C# 知识回顾 - 委托 delegate (续)

    C# 知识回顾 - 委托 delegate (续) [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6046171.html 序 上篇<C# 知识回 ...

  2. spring remoting源码分析--Hessian分析

    1. Caucho 1.1 概况 spring-remoting代码的情况如下: 本节近分析caucho模块. 1.2 分类 其中以hession为例,Hessian远程服务调用过程: Hessian ...

  3. 数塔问题(DP算法)自底向上计算最大值

    Input 输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数 ...

  4. PHP设计模式(三)抽象工厂模式(Abstract Factory For PHP)

    一.什么是抽象工厂模式 抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足以下条件: 系统中有多个产品族,而系统一次只可能消费其中一族产品. 同 ...

  5. MyBatis源码分析(一)开篇

    源码学习的好处不用多说,Mybatis源码量少.逻辑简单,将写个系列文章来学习. SqlSession Mybatis的使用入口位于org.apache.ibatis.session包中的SqlSes ...

  6. [转载]SQL语句中的日期计算

    1. 本月的第一天SELECT  DATEADD(mm,  DATEDIFF(mm,0,getdate()),  0) 2. 本月的最后一天SELECT  dateadd(ms,-3,DATEADD( ...

  7. SQL-类型转换函数

    CAST ( expression AS data_type)CONVERT ( data_type, expression,[style]) Select '您的班级编号'+ 1  错误这里+是数学 ...

  8. hbase集群安装与部署

    1.相关环境 centos7 hadoop2.6.5 zookeeper3.4.9 jdk1.8 hbase1.2.4 本篇文章仅涉及hbase集群的搭建,关于hadoop与zookeeper的相关部 ...

  9. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):

    org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): da.huying.usermanag ...

  10. 小丁带你走进git世界一-git简单配置

    小丁带你走进git世界一-git简单配置 1.github的简单配置 配置提交代码的信息,例如是谁提交的代码之类的. git config  –global user.name BattleHeaer ...