英文原文: http://www.cs.wustl.edu/~schmidt/PDF/HS-HA.pdf
http://www.cs.wustl.edu/~Schmidt/PDF/PLoP-95.pdf
摘要
这篇文字介绍了半同步半异步模式,这个模式运用在复杂的并行系统中,把同步和异步I/O模型集成在一起,既保持了编程简单又保证了执行的效率。这个模式中,高层使用同步I/O模型,简化编程。低层使用异步I/O模型,高效执行。各种操作系统和其它复杂的并行系统中广泛使用这个模式,使用这个模式的操作系统有:UNIX, Mach,Windows NT,and VMS。
1 意图
在系统中分离了同步I/O和异步I/O的两个过程,既简化了并行程序实现的复杂,又不会影响执行的效率。
2 动机
如图一所示,为了说明半同步半异步模式,我们来考虑一个软件架构,BSD UNIX[1]的网络子系统。BSDUNIX的内核负责协调异步通信设备(如:网络适配器、远程终端)和应用程序之间的I/O行为。数据包随时到达设备,产生硬件中断,然后由中断处理例程把数据交给操作系统内核。这些中断处理例程接收数据,触发上层的网络协议处理(如IP,TCP和UDP)。应用数据包在套接口层排队。操作系统把这些数据包分发给每个用户进程。用户进程使用系统调用read,以同步的方式接收套接口层的数据。用户进程可以在任意时刻调用read,当数据没有到达的时候,进程将一直阻塞等待。
在这个体系中,操作系统内核响应设备的中断,执行异步的I/O。而用户级的应用程序进行同步的I/O。这正是“半同步半异步”这个名字的由来,这个结构满足下面的两个需要:
编程实现简单。异步I/O模型中,中断随时触发输入和输出操作,编程复杂。使用异步I/O模型,当中断处理例程拥有线程控制权时,会产生非常麻烦的时序和竟争问题。而且,使用中断机制的程序要求额外的数据结构,这个数据结构用于在异步事件发生的时候保存进程上下文状态。并且,程序执行的时候,外部的事件会在不固定的时间发生,程序不容易调试。
与其相比,使用同步I/O模型的时候,I/O操作在确定的点发生,编程实现要容易的多。此外,同步I/O操作的程序会阻塞等待I/O操作的完成。进程运行上下文的活动记录自动在运行栈中保存,不必使用独立的数据结构。因此,为了让编程简单,有强烈的理由使用同步I/O模型。
程序执行高效。在中断驱动的设备上,异步I/O模型运用带来了高效率。异步I/O让通信和计算同时进行。并且,因为程序运行状态的数据量相对较小,上下文切换的消耗被最小化[2]。因此,为了提高运行的性能,也有强烈理由使用异步I/O模型。
与其相比,如果每种资源的事件(例如网卡,终端和计时器)占用一个独立的活动对象(进程或线程),一个完全同步I/O模型效率会低。每个活动对象包含多个资源(例如栈,寄存器),每种资源都会让它阻塞,等待资源事件的发生。在创建,调度,分发和终止这些独立的活动对象,会消耗更多的时间和空间。
3 方案
编程简单和高效率执行是矛盾的,半同步半异步模式目的正是为了解决这个矛盾。这个模式集成了同步和异步两种I/O模式,结构清晰,效率高。在这个模式中,上层的任务(如:数据库查询,文件传输)使用同步I/O模型,简化了编写并行程序的难度。而底层的任务(如网络控制器的中断处理)使用异步I/O模型,提供了执行效率。一般情况下,上层的任务要比下层的任务多,使用一个简单的层次实现异步处理的复杂性,可以对外隐藏异步处理的细节。另外,同步层次和异步层次任务间的通信使用一个队列来协调。
4 应用
半同步半异步模式在下面的场景中使用。
× 一个系统中的进程有下面的特征:
系统必须响应和处理外部异步发生的事件,
如果为每一个外部资源的事件分派一个独立的线程同步处理I/O,效率很低。
如果上层的任务以同步方式处理I/O,实现起来简单。
× 一个或多个任务必须在单独的控制线程中执行,其它任务可以在多线程中执行。
例如,X Window和Sun RPC的库函数许多是不可重入的。多个控制线程不能安全地同时调用这些函数。然而,为了使多个CPU提高服务的质量,有必要使用并行,不同的线程同时执行批量数据的传输或数据库的查询。使用半同步半异步模式,可以在多线程中分离出单独的线程。在不改变现有代码的情况下,这个分离可以让不可重入的函数在并行环境正确执行。
5 结构和组成单元
图二显示了半同步半异步模式的组成结构。这些组成单元如下描述
×同步任务层(用户级的进程)
本层的任务完成上层的I/O操作,使用同步I/O模型,通过队列层的队列中传输数据。和异步层不同,同步层的任务使用活动对象[3]执行,这些活动对象有自己运行栈和寄存器状态。当执行同步I/O的时候,他们会被阻塞/睡眠。
×队列层(套接口层)
这个层在同步任务层和异步任务层之间,提供了同步控制和缓存的功能。异步任务的I/O事件被缓存到消息队列中,同步任务层在队列中提取这些事件(相反方向亦然)。
×异步任务层
处理低层的事件,这些事件由多个外部的事件源产生(例如网卡,终端)。和异步任务不同,此层的实体是被动对象,没有自己的运行栈,要求不能被阻塞。
×外部事件源(网络接口)
外部设备产生事件,产生的事件先被异步任务层接收和处理。
6 协作
图三展现了一个动态的过程:当外部事件到达后,半同步半异步模式的各个组成单元协作和处理。把协作的过程分成下面三个阶段:
×异步阶段。通过中断机制或异步事件通知,外部的事件源和异步任务层完成交互。
×排队阶段。队列层的队列提供了一个同步控制机制,响应输入事件,缓存同步层和异步层之间的消息,
×同步阶段。同步任务层在队列层提取消息。注意,同步层和异步层专递数据的协议是独立的,和队列层具体处理通信的方式无关。
在图三中,同步层和异步层之间的通信使用生产者/消费者模型。理解这个模型的关键是:完成同步任务的是活动对象。他们可以在任意时刻阻塞调用read或在write。如果数据没有准备好,这些活动对象可以一直等待。相反的,异步任务层的实体是被动对象。他们不能被阻塞。这些对象被通知或外部对象触发。
7 结果
半同步半异步模式有下面的优点
×上层的任务被简化,这是因为不需要再面对底层的异步I/O。复杂的并发控制,中断处理和计时操作都委托给异步任务层。异步层负责处理底层的细节,如,异步系统编程的中断处理。异步任务层管理与硬件相关的组件间(如DMA,内存管理,设备寄存器)的交互。
×不同层可以使用不同的同步策略。每一层不必使用相同的并行控制方式。例如,在单线程的BSD UNIX内核中,异步任务层使用低级的机构(如修改CPU的中断级别)。与此不同,用户级的进程使用高级的同步机构(如使用信号量,消息队列,条件变量,记录锁)。
×层间的通信被限制在单独的一点,因为所有的交互使用队列层协调。队列层对两层之间的消息进行缓存。如果直接通信,同步和异步任务层直接访问对方的内存,就必须使用复杂的锁和时序控制。
×在多处理器环境中提高了性能。使用同步的I/O可以简化编程和提高性能。例如,长时间的数据传输(如从数据库中加载一个大的医学图象)使用同步I/O效率更高。因为一个处理器单独为一个线程使用,可以更有效的使用CPU的指令和数据的缓存。
半同步半异步模式有下面的缺点