KeyFC欢迎致辞,点击播放
资源、介绍、历史、Q群等新人必读
KeyFC 社区总索引
如果你找到这个笔记本,请把它邮寄给我们的回忆
KeyFC 漂流瓶传递活动 Since 2011
 

[M] Prelude to K.O. (2)

[ 6214 查看 / 2 回复 ]

昨天说到了,K.O.(KeyFC Open Translation Toolset)采用了代号为Chobits Application Server(CAS)的架构。
今天谈一下CAS的内部结构。

--- 消息队列 ---

CAS区别于一般模块化设计的特点就是,模块之间的关系是消息传递而不是控制传递。
既然是消息传递,队列是不可少的了。

每一个CAS服务模块至少带有一个消息队列:
服务请求从其他模块发送到此队列中;此模块的服务线程获取请求,执行处理并且根据情况作出回复;回复仍然是以消息形式,从此模块发送到其他模块的队列中;


(图1)

前面提到,CAS能够使程序员(基本上)用传统的单线程程序思路写出很容易的稳定的多线程的应用程序,消息队列在其中扮演了重要的角色。
消息队列就像一个"同步防火墙",将绝大多数的多线程同步操作隔离在服务模块代码之外;交给模块编程者的,是一个简洁,稳定的单线程环境。

因为需要被多个线程同时访问,消息队列本身需要对其所有操作进行线程同步(Thread Synchronization)以避免“竞态条件”(Race Condition)...
经典的做法是使用操作系统提供的同步对象,比如互斥(Mutex)、信号灯(Semaphore)、临界区(CriticalSection)等...
但是由此带来的问题是程序执行效率的降低,特别是在多处理的环境下,随着处理器数量的增多,同步效率急剧下降...

但是,我们可以注意到CAS消息队列本身结构很简单:
相对于传统的Grid Computing中的MPI消息传递,CAS有一个绝对的优势,就是模块之间内存可以共享(因为处于同一个进程中)。
这样CAS消息传递本身也就能够被极大的优化——所谓一条消息,其实也就是一个指针、4个字节而已(x86结构下)。
因此,实现消息队列也就可以应用另一项同步技术——免锁同步(Lock-free Synchronization)。

免锁同步相对于传统技术有很多优势,主要两点:在多处理器环境同步效率高;无死锁问题 (因为根本就没有用锁=v=)。
具体技术细节,请使用Google学术搜索查找相关论文。 http://scholar.google.com
经过实际测试(4生产线程+4消费线程),
在单处理器环境下,免锁CAS消息队列 基本与 临界区同步CAS消息队列 性能相当;
双处理器,免锁队列同步效率要高5%—30%;
四处理器,免锁队列同步效率要高80%—300%;
(如谁有八个或更多处理器的机器,欢迎联系我获取测试程序!^_^)


--- 消息接口 与 消息总线 ---

前面提到了模块之间依靠相互交换消息来完成一系列的操作。
那么,聪明的各位一定会问:一个模块怎么知道另一个模块的消息队列在什么地方,又怎么去传递消息呢?

回忆一下,我一开始就提到,CAS架构的宗旨就是“极大模块化”程序的设计和实现。
对于应用模块编写者来说,CAS消息机制本身就是一套与应用模块无关的功能;
消息相关的功能可以完全的模块化出来,"眼不见心不烦"。

因此,在实际的CAS架构下,模块是看不到消息队列的,不论是自己的还是其他模块的;看得到的只是消息接口(Interface)。
消息接口提供给模块一套基本的功能:获取自己消息队列的消息,查询其他模块的接口编号,发送一个封装好的消息(消息中包含接受方的接口编号)。
至于消息队列的管理以及消息的传递是如何进行的,统统不用操心,一切都由这个消息模块完成。

这个消息模块,就是消息总线(Message Bus)。
一个模块载入时,需要提供一个模块名称和一个GUID(唯一序列号)给消息总线,消息总线为这个模块注册一个消息队列,并将接口返回给该模块;
于是,这个模块就可以利用消息接口向总线上其他已注册的模块发送消息,其他的模块也可以通过总线查询到这个模块的接口编号...


(图2)

需要提起的是,消息总线提供给模块两种发送消息的方法:传送和投递。
传送是由发送方的线程直接将消息放入接受方的队列中;而投递则是将消息交给总线,由总线调度将消息传送给接受方。
两种方法各有所长:
* 投递 的优点是消息发送速度快,适合需要向很多模块发送大量消息的场合(比如媒体文件的播放 / 动画特效的渲染);但是当接受方的队列阻塞(一定时间)时,消息将会被自动释放,因此不适合要求可靠传递的消息(向一个文件写数据)。
* 传送 则保证消息投放入接受方的队列,如果有任何原因无法传送,发送方肯定会得知,并且可以按预定动作处理这一事件。

------

今天谈的这一些是CAS的基础的结构,下次我将谈谈这个结构如何工作:CAS消息的传递 (仍然是自然语言描述,不涉及具体API)。
最后编辑Prz 最后编辑于 2007-05-11 13:41:27
本主题由 管理员 深海蓝空 于 2007/5/13 13:28:46 执行 设置精华/取消 操作
分享 转发
飛べない翼に、意味はあるんでしょうか?
TOP

回复: [M] Prelude to K.O. (2)

原帖由 Prz 于 2007-5-11 13:38:00 发表
但是,我们可以注意到CAS消息队列本身结构很简单:
相对于传统的Grid Computing中的MPI消息传递,CAS有一个绝对的优势,就是模块之间内存可以共享(因为处于同一个进程中)。
这样CAS消息传递本身也就能够被极大的优化——所谓一条消息,其实也就是一个指针、4个字节而已(x86结构下)。
因此,实现消息队列也就可以应用另一项同步技术——免锁同步(Lock-free Synchronization)。


实际使用中多数消息都是很简短的,如果每次都传一个指针,同步问题是可能避免,但频繁的内存分配和释放(消息可能是不定长的)则更成问题.

我希望后面的文章能相信阐述一下消息的结构问题.要避免模块之间的耦合,则必须要消息统一化.否则某个模块的消息结构改变,其他发送过此消息的模块也要跟着改变.而消息的统一化不是很简单的,除了一个例外,就是所有消息都使用一个字符串,当然每个模块都要面临字符串的匹配和效率问题.

纯消息处理的架构颠覆了传统的编程思想,许多需要持续完成的工作就不得不利用麻烦的状态机来控制.
比如给日志记录模块发送一个"传送"消息之后,要等待日志记录返回"记录正确"的消息后才能继续下一步,
在等待返回的消息前做什么呢?
* 如果等待,则不符合架构的特性,这段时间可能许多消息不能及时处理,甚至会出现消息死锁.
* 如果处理下一个消息循环,则保存当前运行的状态就要用到状态机.如果连续执行的任务比较多,则会变得很复杂.

总的来说,这种架构比较接近人的思维,在分布式计算或人工智能领域会得到很好的利用.
但也有许多简单的情况会使编程变得更复杂,调试变得更困难.
任何架构都不可能全部都会体现出优点.即使是我很赞赏的COM架构也有其不足.
最后编辑dwing 最后编辑于 2007-05-11 16:05:01
TOP

回复:[M] Prelude to K.O. (2)

感谢楼上的捧场.... 看来对于编程感兴趣的人还真的是不多啊 -v-...
(其实我也不期望什么,因为一直觉得我做的这个架构非常缺乏文档,正好趁这个机会将技术细节记录下来,免得以后忘了:P)

楼上确实属于我所提到的"聪明的读者" :D 每次提出的问题正好就是我下一次计划要讲的...
您的问题CAS都有对应的解决方法,虽然不说是完美的,但是应该可以被接受。

套话: 欲知细节,请待下回分解。
飛べない翼に、意味はあるんでしょうか?
TOP