31.5. 吃蛋糕时间
能够将一组流片段当作逻辑连续的数据流之后,ACE_Message_Block通信流对付起来顿时变得简单多了,我希望你也同意这个看法。在我们的中间件项目中,这让我们能够将高层协议消息解包为对象,当然还需要搭配另外一个实例适配器和一个消息工厂。请允许我稍微跑下题,介绍一个相关背景,澳大利亚标准定义了一个叫做AS2805的协议,用于实现电子支付系统。这是一个非常灵活的协议,但是也有一个显著缺陷:消息的首部格式固定,但其中没有携带任何长度信息,并且消息域的个数可变,某些域的长度也可变。这就是说,除非完整地解析消息,否则你连对端是否发送完毕都不可能知道。因而,解决问题的关键在于让这个解析过程轻松高效。
这个目标已经达到了,方法是在acestl::message_queue_sequence实例之上应用另一个实例适配器,从而把前者当作一个“流式”(streamable)对象来处理,类似于CreateStreamFromLockBytes()把逻辑连续的ILockBytes实例转变成流式对象。流式对象由消息工厂使用,后者理解如何从报文首部读取消息类型,然后据此指派合适的解析函数读取剩余内容,最后创建相应的消息实例。如果数据不够,调用工厂的方法只是温和地返回失败,队列的数据不会改变,直到发生下一次I/O事件。只有一条消息被完整地接收之后,它占用的队列前部空间才被删除并释放回内存缓冲区。如果解析消息内容失败,那就是对端发送了错误数据,连接将被切断。
31.5.1. 再快些!
现在我们已经拥有了一些很好的抽象——部分已经服务于大规模部署的系统,这都是不可小觑的事实——但是潜意识中的多疑还是让你无法安心。我们操纵的内存块是连续的,但受限于acestl::message_queue_sequence::iterator的本质,却必须逐个处理块中的字节。肯定有效率上的代价。确实如此。
在继续讨论之前,我先提出一个众所周知关于性能的观点,即“不要过早优化”。尽管有简化问题之嫌,但还是可以讲得更明确一些,那就是在某个时刻的某个系统,通常都只有一个性能瓶颈;很多低效都是在某个更重大的低效被解决后才浮出水面。我在很多应用中都用过message_queue_sequence,而它从未和性能瓶颈沾边。然而,我还是有点“效率强迫症”——这是什么?你注意到过吗?——加上STLSoft是一个公共的开源项目,万一message_queue_sequence在别人的项目中成为瓶颈, 那可就糟糕了。所以我想让你看看如何熊掌和鱼兼得,也就是说,如何以STL序列线性化数据块的内容,同时又保持类似直接使用数据块的效率。
【责任编辑:
董书 TEL:(010)68476606】