◆◆◆
并发软件中的服务处理通常是异步和同步同时存在。异步用于高效地处理底层系统服务,同步则用于简化应用服务处理。要想从两种编程模型中均获益,高效地协调异步和同步服务处理是非常重要的。
异步和同步服务处理通常是相关联的。例如,Web服务器的I/O层往往使用异步读操作来取得HTTP Get请求[HP97]。而在CGI层对GET请求的处理则同步地运行于独立的控制线程。在I/O层异步到达的请求必须与CGI层对请求的同步处理集成在一起。换一个角度,我们再来看看Web客户端,AJAX可以使用异步JavaScript和XML(asynchronous JavaScript and XML)来提高Web客户端的可感知响应速度[Gar05]。通常,异步和同步服务应该相互协作、取长补短。
因此:
将并发软件的服务分解为异步和同步两层,然后增加一个队列层来处理二者直接的交互。
使用单独的线程或者进程以同步的方式处理高层服务,比如领域功能、数据查询或文件传输,而由网络硬件中断所驱动的短暂(short-lived)协议处理程序等底层系统服务则应该采用异步方式。如果同步层的服务必须和异步层的服务通信,则应当采用排队层交换消息的方式进行。
◆◆◆
HALF-SYNC/HALF-ASYNC模式对这三层进行了严格的划分,这使得并发软件更容易理解、调试和改进。而且,异步和同步服务各自的缺陷也不会出现相互传染:异步服务的性能不会因为同步服务被阻塞而降低,同步服务的编程简单性也不会受到异步复杂性(比如显式的状态管理)的影响。最后,使用排队层可以避免对异步和同步服务层之间的依赖进行硬编码,同时也可以简化消息处理的优先级排序。异步层和同步层的严格解耦合要求这两层之间的通信必须或者使用COPIED VALUES——这样就会带来性能上的损失和资源管理上的消耗,因为有更多的数据需要传送;或者使用IMMUTABLE VALUES表示——这种做法相对来说属于轻量级的方式,但是其构造上可能更为复杂。
总的来说,HALF-SYNC/HALF-ASYNC通过使用LAYERS(185)来保证三个不同的执行模型(model)和通信模型的独立性和封装性。
同步层服务,比如数据库查询、文件传输或者领域功能通常运行在自己的线程中,以便多个服务可以同时执行。如果一个服务实现为ACTIVE OBJECT(365)它便可以同时处理多个服务请求,从而提高应用的性能和吞吐量。
异步层的服务可以通过异步中断或者支持异步I/O的操作系统API实现,后者包括Windows重叠I/O(Windows overlapped I/O)和I/O完成端口(I/O completion ports)[Sol98],或者POSIX异步I/O aio_*族系统调用[POSIX95]。WRAPPER FACADES (459)用于将与平台相关的异步I/O功能封装成统一的接口,藉此简化异步层的正确使用和跨平台移植。如果我们将HALF-SYNC/HALF-ASYNC设计成与PROACTOR或者REACTOR事件处理基础设施联合使用,这个事件处理基础设施便是所谓的异步层。虽然REACTOR并非是真正的异步,但如果它的服务实现的是短暂(short-duration)操作,而不是长时间的阻塞,你就会发现它其实具有异步的关键属性。
排队层通常是由同步层和异步层所有服务共享的消息队列组成。复杂的排队层可以提供多个消息队列,比如为每个消息优先级或者通信端提供一个消息队列。消息队列可以实现为MONITOR OBJECTS(368),这样就可以使得异步和同步服务能够对消息队列进行透明的串行访问。TEMPLATE METHODS(453)和STRATEGIES(455)用于支持对消息队列不同方面的设置,例如配置其排序、串行化、通知和流程控制的行为。STRATEGIES相对更为灵活,它可以为消息队列提供更松的耦合度,并支持运行时配置和重配置。TEMPLATE METHODS则更适合于仅需要编译期灵活性的情况。由排队层进行路由的信息封装在MESSAGES(420)里面。
15.2 Leader/Followers **
在开发并发软件,尤其是并发ENCAPSULATED IMPLEMENTATION(313)或者应用了REACTOR(259)作为事件处理基础设施的网络服务器时…
…我们常常需要并行而高效地响应和处理从多个事件源发起的不同事件。