http://zhenyulu.cnblogs.com/articles/27432.html
源代码下载:未经改造的ActiveObject;利用Timer对象改造后的ActiveObject
关于ActiveOjbect模式,第一次是在Robert C. Martin的《敏捷软件开发-原则、模式与实践》一书中看到的,后来找到了ActiveObject的出处:Lavender的《Active Object An Object Behavioral Pattern for Concurrent Programming》,才发现Active Object模式比我想象中的还要复杂,功能还要强大。它模拟实现了一种异步的、多线程的控制模式,为许多工业系统提供了一个简单的多任务核心。
《敏捷软件开发》中给出了一个Java实现的例子,从一个侧面表现了ActiveObject的使用方法。该例子通过ActiveObject引擎对命令队列中的命令进行循环处理,实现了命令的延时调用。其关键算法可以描述如下:
1、构造一延时命令,该延时命令将包含一任务并记录开始时间
2、将该延时命令放入队列。
3、从队列中取出一命令,若是延时命令,则判断是否到时,若尚未到时,则转向第2步。若到时,则释放出包含的任务到队列中。
4、判断是否是循环延时任务,如果是,则重新记录开始时间,并转向第 2 步。
5、转向第 3 步。
我将其改为了C#代码,关键代码如下:
下面是用Together生成的UML图:
整个C#源代码可以从这里下载(.net 1.1下调试通过)
在该代码的应用中发现,一旦使用上该模式,CPU的占用率就达到了100%。也难怪,在任务比较轻的情况下,ActiveObject引擎绝大多数的时间都是在做一些无用功:从队列取出Command,看看是否到时,没有的话再把它放回到队列中。这些无用功占用了大量的CPU时间。即使创建一个新线程运行引擎,将线程的优先级别设置为ThreadPriority.BelowNormal,也避免不了CPU占用100%的问题。只不过此时用户不会感受到有任何迟滞而已(因为线程的优先级是BelowNormal)。
至此,能否更为有效的使用ActiveObject模式成了项目需要解决的一个关键问题。Windows中的Timer控件给了我一些启发:Timer控件可以定时触发事件,但从来不占用大量的CPU时间。如果简单的周期性任务,使用Timer非常简便(例如:每秒更新一下窗口上时钟的显示),但面对动态增加的,变化的周期性任务,使用Timer控件就显得有些麻烦(例如:每秒更新时间显示、每1.7秒读取一个数据、每2.3秒发送一条消息....),我们很容易想象到通过动态添加删除Timer控件来达到上述目的所面临的麻烦。如果能够将ActiveObject模式与Timer的优点结合起来,就可以构建一个高效、灵活的ActiveObject实现方案。下面是我的实现方案:
1、构造一Timer对象
2、遍历队列,执行已经到时的任务并计算距离最近一次事件触发还需多少时间
3、根据步骤 2 的结果设置Timer对象的下一次触发时间
4、Timer对象触发事件 2
通过将整个过程置于一个单独线程中执行,并在ActiveObject引擎空闲的时候,用WaitOne方法归还CPU占用以达到降低CPU占用率的问题。关键代码如下:
改造后的C#源代码可以从这里下载。修改后的ActiveObject模式UML图如下:
经过测试,改造后的ActiveObject引擎运行时CPU占用率急剧下降,在我的机器上平均CPU占用率只有不到2%,这大大提高了系统执行效率。
测试代码如下: