服务器公共组件实现 -- 消息队列
来源:互联网 发布:照片设计软件 编辑:程序博客网 时间:2024/06/15 20:20
既然说到了消息队列,那我们继续来稍微多聊一点吧。
我们所能想到的最简单的消息队列可能就是使用stl的list来实现了,即消息队列内部维护一个list和一个互斥锁,putMessage时将message加入到队列尾,getMessage时从队列头取一个message返回,同时在getMessage和putMessage之前都要求先获取锁资源。
实现虽然简单,但功能是绝对满足需求的,只是性能上可能稍稍有些不尽如人意。其最大的问题在频繁的锁竞争上。
对于如何减少锁竞争次数的优化方案,Ghost Cheng提出了一种。提供一个队列容器,里面有多个队列,每个队列都可固定存放一定数量的消息。网络IO线程要给逻辑线程投递消息时,会从队列容器中取一个空队列来使用,直到将该队列填满后再放回容器中换另一个空队列。而逻辑线程取消息时是从队列容器中取一个有消息的队列来读取,处理完后清空队列再放回到容器中。
这样便使得只有在对队列容器进行操作时才需要加锁,而IO线程和逻辑线程在操作自己当前使用的队列时都不需要加锁,所以锁竞争的机会大大减少了。
这里为每个队列设了个最大消息数,看来好像是打算只有当IO线程写满队列时才会将其放回到容器中换另一个队列。那这样有时也会出现IO线程未写满一个队列,而逻辑线程又没有数据可处理的情况,特别是当数据量很少时可能会很容易出现。Ghost Cheng在他的描述中没有讲到如何解决这种问题,但我们可以先来看看另一个方案。
这个方案与上一个方案基本类似,只是不再提供队列容器,因为在这个方案中只使用了两个队列,arthur在他的一封邮件中描述了这个方案的实现及部分代码。两个队列,一个给逻辑线程读,一个给IO线程用来写,当逻辑线程读完队列后会将自己的队列与IO线程的队列相调换。所以,这种方案下加锁的次数会比较多一些,IO线程每次写队列时都要加锁,逻辑线程在调换队列时也需要加锁,但逻辑线程在读队列时是不需要加锁的。
虽然看起来锁的调用次数是比前一种方案要多很多,但实际上大部分锁调用都是不会引起阻塞的,只有在逻辑线程调换队列的那一瞬间可能会使得某个线程阻塞一下。另外对于锁调用过程本身来说,其开销是完全可以忽略的,我们所不能忍受的仅仅是因为锁调用而引起的阻塞而已。
两种方案都是很优秀的优化方案,但也都是有其适用范围的。Ghost Cheng的方案因为提供了多个队列,可以使得多个IO线程可以总工程师的,互不干扰的使用自己的队列,只是还有一个遗留问题我们还不了解其解决方法。arthur的方案很好的解决了上一个方案遗留的问题,但因为只有一个写队列,所以当想要提供多个IO线程时,线程间互斥地写入数据可能会增大竞争的机会,当然,如果只有一个IO线程那将是非常完美的。
- 服务器公共组件实现 -- 消息队列
- 服务器公共组件实现 -- 消息队列
- Mangos源码分析(8):服务器公共组件实现之消息队列
- Mangos源码分析(8):服务器公共组件实现之消息队列
- Mangos源码分析(8):服务器公共组件实现之消息队列
- Mangos源码分析(8):服务器公共组件实现之消息队列
- 服务器公共组件实现 -- 状态机
- 服务器公共组件实现 -- 状态机
- 服务器公共组件实现1
- 服务器公共组件实现2
- 服务器公共组件实现 -- 环形缓冲区
- 服务器公共组件实现 -- 发包的方式
- 服务器公共组件实现 -- 环形缓冲区
- 服务器公共组件实现 -- 发包的方式
- System V消息队列实现服务器
- 服务器公共组件实现 -- mangos的游戏主循环
- 服务器公共组件实现 -- 继续来说主循环
- 服务器公共组件实现 -- mangos的游戏主循环
- javascript 常见错误(失误足迹)
- Oracle Date类型与SQLT_DAT分析
- linux远程登录遇到的问题
- Eclipse及其插件介绍和下载 (3)
- Linux下使用VirtualBox安装并配置Windows服务器
- 服务器公共组件实现 -- 消息队列
- Struts入门经验
- 第一篇BLOG
- 自动化测试是不是能达到90%甚至100%的覆盖率?
- 怎么样养成整洁有序的习性
- 学点什么?
- 引用变量和变量的值(Referencing Variables and Variable Value)
- 昨天刚装好了oracle10g却总是碰到RemoteOperationException: ERROR: Wrong password for user;
- DVBPSI中PAT PMT 编码函数注解