Pennant的日常
分享工作上的点点滴滴

5.3半同步/半异步

1.问题

      并发系统通常既包含异步处理服务,又包含同步处理服务。系统程序员有充分的理由使用异步特性改善性能。异步程序一般更高效,因为可以直接将服务映射为异步机制,如硬件中断处理程序或者软件信号处理程序。

      相反,应用程序员也有充分的理由使用同步处理简化他们的编程强度。通常同步程序更简单。因为可以限制某些服务在处理序列中的良好定义的点上运行。

      因此,在定义一个既有同步又有异步执行服务的软件体系结构时,必须解决两个强制条件:

      1)该体系结构应该这样设计:需要同步处理的简易性的应用程序开发者无需考虑异步的复杂性。同时,必须将性能最大化的系统开发者不需要考虑同步处理的低效性。

      2)该体系结构应该让同步和异步处理服务能够相互通信,而不会使它们的编程模型复杂化或者过度地降低它们的性能。

      虽然对编程的简易性和高性能二者的需求可能看起来相互矛盾,但是在一些具体并发系统中需要解决这两个强制条件。

 

2.解决方案

      将系统中的服务分解成两层,同步和异步,并且在它们之间增加一个排队层协调异步和同步层中服务之间的通信。

      细节:在独立线程或进程中同步地处理高层服务(如耗时长的数据库查询或文件传输),从而简化并发编程。相反,异步地处理底层服务(如由网络接口硬件发出的中断所驱动的短期协议处理程序),以增强性能。如果驻留在相互独立的同步和异步层中的服务必须相互通信或同步它们的处理,则应允许它们通过一个排队层向对方传递消息。

 

3.结构

      同步服务层(Synchronous service layer)完成高层处理服务。同步层中的服务在独立的操作时可以阻塞的线程或进程中运行。

      异步服务层(Asynchronous service layer)进行低层处理服务,这些低层处理服务通常由一个或多个外部事件源发出。异步层中的服务在进行操作时不能阻塞,而不会过度不为降低其他服务的性能。 

      

 

      排队层(queueing layer)为同步和异步层服务之间提供通信机制。 例如,异步服务产生包含数据和控制信息的消息,然后将这些消息缓冲保存在排队层中,以后同步服务可以获取它们,反之亦然。当消息从另外的层传递给某一层时,排队层负责通知这一层中的服务。因此排队层使异步和同步层可以以“生产者/消费者”方式交互,类似于管道和过滤器模式中定义的结构。

      外部事件源(external event source)产生被异步服务层接收和处理的事件。

       

 

4.实现

1)将整体系统分解为三层:同步层、异步层和排队层。

  1.1)标识高层和/或耗时长的服务并将它们装配到同步层中。并发系统中的许多服务在使用同步处理编程的时候更容易实现。这些服务通常进行相对高层或耗时长的应用处理,如传输Web服务器中的大容量数据流或者进行数据库的复杂查询。因此同步层的服务应该运行在独立的进程或线程中。如果没有可用的数据,那么服务可以在端到端应用程序通信协议的控制下在排队层中阻塞,等待响应。

  1.2)标识低层和/或耗时短的服务并将它们配置到异步层中。系统中的某些服务由于延时不能阻塞。这种服务一般实现与外部事件源交互的低层或耗时短的系统处理,如用户终端或由中断驱动的硬件网络接口。为了将反应能力和效率最大化,这些事件源必须尽快得到处理并且不能阻塞为它们服务的线程。它们的服务应该被从外部事件源发出的异步通知或中断触发并一直执行到结束,这时它们可以将包含结果的消息插入排队层。

  1.3)标识层间通信策略并将它们装配到排队层中。排队层是一个中介者,将异步层和同步层服务之间的通信分离开。这些服务就不会彼此进行直接访问,反通过排队层互相访问。排队层实现的与通信相关的策略包括多路复用(分解)、缓冲、通知和流控制。异步层和同步层中的服务使用这些排队策略实现在同步层和异步层之间传递消息的协议。

2)实现同步层中的服务。同步层中的高层和/或耗时长的服务通常使用多线程和多进程技术实现。与线程相比,进程包含更多的状态信息并需要更多的开销来生成、同步化、调度和相互通信。因此,在独立的线程中比在独立的进程中实现同步服务可以使应用程序更简单和更高效。

    然而,多线程会降低应用程序的健壮性,因为进程中独立的线程会相互干扰。例如,一个错误线程可能破坏由进程中的其他线程共享的数据,并因此产生不正确的结果,使进程崩溃,或导致进程永久性挂起。因此,为了增加健壮性,可以在独立的进程中实现应用程序服务。

3)实现异步层中的服务。异步层中的低层和/或耗时短的服务通常没有它们自己专有的控制线程。它们必须从其他地方借用一个线程,如操作系统内核的“空闲线程”或一个独立的中断堆栈。为了确保对其他系统服务(如高优先级硬件中断)有足够的反应时间,这些服务必须异步地运行并且不能被长时间阻塞。

    下面是两个可以用来触发异步服务执行的策略:

    ·异步中断。该策略通常在开发被外部事件源(如网络接口或磁盘控制器)发出的硬件中断触发的异步服务时使用。在这种策略中,当事件在一个外部事件源上发生时,中断通知与事件关联的处理程序,然后该处理程序处理事件直到结束。

    在复杂的并发系统中,可能有必要定义中断层次(hierarchy)来允许不太关键的处理程序被拥有更高优先级的处理程序占先。为了防止中断处理程序在被访问时破坏共享状态,必须保护被异步层使用的数据结构,例如可以采用提高中断优先级的方式。

    ·主动I/O。这种策略常用于开发基于高层操作系统API。如Windows NT重叠I/O和I/O完成端口或者异步I/O系统调用的POSIX aio_*系列的异步服务。在这种策略中,I/O操作由异步操作处理器执行。一个异步操作完成后,异步操作处理器产生一个完成事件。然后该事件被分配给与事件关联的处理程序,该处理程序处理事件直到完成。

    这两种异步处理策略有个相同的约束:处理程序不可能长时间阻塞而不破坏对来自其他外部事件源的事件的处理。

4)实现排除层。异步层中的服务完成了对来自于外部事件源的输入的处理后,它们一般将结果消息插入排队层。同步层中相应的服务会接着将从排队层中删除这些信息,并对它们进行处理。输出处理时这些角色正好倒过来。在实现排队层时必须定义两个与通信有关的策略。

  4.1)实现缓冲策略。异步层和同步层中的服务不能直接访问对方的内存,而是通过一个排队层交换消息。排队层对消息进行缓冲,这样同步和异步服务可以并发运行,而不是死板地采用“停止并等待”的流控制协议运行。因此缓冲策略必须实现一个排序、串行化、通知和流控制策略。注意,策略模式可以用来简化选择的策略的配置。

    ·实现排序策略。简单的排队层按到达的顺序存储消息,也就是“先进先出”(FIFO)。被某个层的服务放入队列的第一个消息就是第一个被另一个层中的服务移出的消息。FIFO排序易于实现,但是如果高优先级的消息在低优先级消息之后入队列,可能会导致优先级倒置。因此,可以使用更复杂的队列策略,按“优先级”顺序存储和获得消息。

    ·实现串行化策略。异步层和同步层中的服务可以并发地执行。因此队列必须被串行化以避免消息被并发插入和删除时出现的竞争条件。这种串行化通常使用简单同步机制(如互斥机制)实现。这种机制确保消息可以被插入到排队层的消息缓冲区和从中删除,而不会破坏它的内部数据结构。

    ·实现通知策略。在从一层向另一层发送的消息到达时,有必要通知该层的服务。通常使用更高级和更复杂的同步机制(如信号灯或条件变量)实现由排队层提供的通知策略。这些同步机制可以在发给同步层或异步层的数据到达排队层时通知同步层或异步层中的相应服务。

    ·实现流控制策略。系统不可能提供无限制的资源量对排队层中的消息进行缓冲。因此,需要控制在同步层和异步层之间传递的数据量。流控制是一种技术,能防止同步服务向异步层发出消息的速度高于消息能在网络接口传输和排队的速度而“淹没”异步层。  

    同步层中的服务可以阻塞。普通的流控制策略在一个同步服务产生和排队超过某一数量的消息时,简单地将它置于睡眠。在异步服务层将队列置空到低于某个水平时,排队层可以唤醒处于睡眠的同步服务,继续它的处理。

    相反,异步层中的服务不能阻塞。如果它们产生过多的消息,那么普通的流控制策略允许排队层取消消息,直到同步服务层完成了对队列中消息的处理。如果消息与一个可靠的面向连接的传输协议(如TCP)关联,发送者将最终超时并重新发送被取消的消息。

  4.2)实现多路复用(分用)机制。在半同步/半异步模式的简单实现中,排队层里只有一个队列。该队列被所有异步层和同步层中的服务共享,任何服务可以处理任何请求。这种配置减轻了对复杂多路复用(分用)机制的需要。在这种情况下,一般的实现是定义一个单件队列,所有服务使用它插入和删除消息。

    在更复杂的半同步/半异步模式的实现中,某个层中的服务可能需要对另一个层中的一些服务发送和接收特定的消息。因此一个排队层可能需要多个队列(如每个服务一个队列)。对于多个队列,需要更复杂的多路分解机制,以确保在不同层的服务间交换的消息放置在相应的队列中,一般的实现是使用某些类型的多路复用(分用)机制(如哈希表)将消息放进相应的队列。

 

5.结论

优点:

1)简化和性能。简化高层同步处理服务的编程,又没有降低低层系统服务的性能。

2)事务分离。分离每一层的同步策略,因此各层不需要使用相同的并发控制策略。

3)集中的层间通信。层间通信集中在一个访问点进行,因为所有交互都由排队层协调。排队层对另外两层间传递的消息进行缓冲。这消除了加锁和串行化的复杂性,否则,如果同步和异步服务层直接访问对方内存中的对象,这就是必要的。

 

不足:

1)当数据在同步和异步服务层之间通过排队层传输时,语境切换,同步化和数据拷贝开销可能会引起越界带来的开销。

2)高层应用程序服务可能不会从异步I/O的效率中获益。

3)调试和测试的复杂性。 

posted on 2012-09-30 21:44  汝熹  阅读(599)  评论(0编辑  收藏  举报