贝贝花花包包店,精品555皮具,钱夹,皮夹

字体: | 推荐给好友 上一篇 | 下一篇

ACE技术论文集-第8章 异步事件多路分离和分派处理器

发布: 2008-6-13 14:40 | 作者: Prashant Jain and D | 来源: 转载 | 查看: 297次

8前摄器Proactor):用于为异步事件多路分离和分派处理器的对象行为模式
 
Irfan Pyarali   Tim Harrison   Douglas C. Schmidt   Thomas D. Jordan
 
 
现代操作系统为开发并发应用提供了多种机制。同步多线程是一种流行的机制,用于开发同时执行多个操作的应用。但是,线程常常有很高的性能开销,并且需要对同步模式和原理有深入的了解。因此,有越来越多的操作系统支持异步机制,在减少多线程的大量开销和复杂性的同时,提供了并发的好处。
本论文中介绍的前摄器(Proactor)模式描述怎样构造应用和系统,以有效地利用操作系统支持的异步机制。当应用调用异步操作时,OS代表应用执行此操作。这使得应用可以让多个操作同时运行,而又不需要应用拥有相应数目的线程。因此,通过使用更少的线程和有效利用OS对异步操作的支持,前摄器模式简化了并发编程,并改善了性能。
 
8.1意图
 
前摄器模式支持多个事件处理器的多路分离和分派,这些处理器由异步事件的完成来触发。通过集成完成事件(completion event)的多路分离和相应的事件处理器的分派,该模式简化了异步应用的开发。
 
8.2动机
 
这一部分提供使用前摄器模式的上下文和动机。
 
8.2.1上下文和压力
 
前摄器模式应该被用于应用需要并发执行操作的性能好处、又不想受到同步多线程或反应式编程的约束时。为说明这些好处,设想一个需要并发执行多个操作的网络应用。例如,一个高性能Web服务器必须并发处理发送自多个客户的HTTP请求[1, 2]。图8-1 显示了Web浏览器和Web服务器之间的典型交互。当用户指示浏览器打开一个URL时,浏览器发送一个HTTP GET请求给Web服务器。收到请求,服务器就解析并校验请求,并将指定的文件发回给浏览器。
 
 
图8-1 典型的Web服务器通信软件体系结构
 
开发高性能Web服务器要求消除以下压力:
 
  • 并发性:服务器必须同时执行多个客户请求;
  • 效率:服务器必须最小化响应延迟、最大化吞吐量,并避免不必要地使用CPU;
  • 编程简单性:服务器的设计应该简化高效的并发策略的使用;
  • 可适配性:应该使继承新的或改进的传输协议(比如HTTP 1.1[3])所带来的维护代价最小化。
 
Web服务器可以使用若干并发策略来实现,包括多个同步线程、反应式同步事件分派和前摄式异步事件分派。下面,我们检查传统方法的缺点,并解释前摄器模式是怎样提供一种强大的技术,为高性能并发应用而支持高效、灵活的异步事件分派策略的。
 
8.2.2传统并发模型的常见陷阱和缺陷
 
同步的多线程和反应式编程是实现并发的常用方法。这一部分描述这些编程模型的缺点。
 
8.2.2.1通过多个同步线程实现的并发
 
或许最为直观的实现并发Web服务器的途径是使用同步的多线程。在此模型中,多个服务器线程同时处理来自多个客户的HTTP GET请求。每个线程同步地执行连接建立、HTTP请求读取、请求解析和文件传输操作。作为结果,每个操作都阻塞直到完成。
同步线程的主要优点是应用代码的简化。特别是,Web服务器为服务客户A的请求所执行的操作在很大程度上独立于为服务客户B的请求所需的操作。因而,很容易在分离的线程中对不同的请求进行服务,因为在线程之间共享的状态数量很少;这也最小化了对同步的需要。而且,在分离的线程中执行应用逻辑也使得开发者可以使用直观的顺序命令和阻塞操作。
 
 
图8-2 多线程Web服务器体系结构
 
图8-2显示使用同步线程来设计的Web服务器怎样并发地处理多个客户请求。该图显示的Sync Acceptor对象封装服务器端用于同步接受网络连接的机制。使用“Thread Per Connection”并发模型,各个线程为服务HTTP GET请求所执行的一系列步骤可被总结如下:
 
  1. 每个线程同步地阻塞在accept socket调用中,等待客户连接请求;
  2. 客户连接到服务器,连接被接受;
  3. 新客户的HTTP请求被同步地从网络连接中读取;
  4. 请求被解析;
  5. 所请求的文件被同步地读取;
  6. 文件被同步地发送给客户。
 
附录A.1中有一个将同步线程模型应用于Web服务器的C++代码例子。
如上所述,每个并发地连接的客户由一个专用的服务器线程服务。在继续为其他HTTP请求服务之前,该线程同步地完成一个被请求的操作。因此,要在服务多个客户时执行同步I/O,Web服务器必须派生多个线程。尽管这种同步线程模式是直观的,且能够相对高效地映射到多CPU平台上,它还是有以下缺点:
 
线程策略与并发策略被紧耦合:这种体系结构要求每个相连客户都有一个专用的线程。通过针对可用资源(比如使用线程池来对应CPU的数目)、而不是正被并发服务的客户的数目来调整其线程策略,可能会更好地优化一个并发应用;
 
更大的同步复杂性:线程可能会增加序列化对服务器的共享资源(比如缓存文件和Web页面点击日志)的访问所必需的同步机制的复杂性;
 
更多的性能开销:由于上下文切换、同步和CPU间的数据移动[4],线程的执行可能很低效;
 
不可移植性:线程有可能在有些平台上不可用。而且,根据对占先式和非占先式线程的支持,OS平台之间的差异非常大。因而,很难构建能够跨平台统一运作的多线程服务器。
 
作为这些缺点的结果,多线程常常不是开发并发Web服务器的最为高效的、也不是最不复杂的解决方案。
 
8.2.2.2通过反应式同步事件分派实现的并发
 
另一种实现同步Web服务器的常用方法是使用反应式事件分派模型。反应堆(Reactor)模式描述应用怎样将Event Handler登记到Initiation Dispatcher。Initiation Dispatcher通知Event Handler何时能发起一项操作而不阻塞。
单线程并发Web服务器可以使用反应式事件分派模型,它在一个事件循环中等待Reactor通知它发起适当的操作。Web服务器中反应式操作的一个例子是Acceptor(接受器)[6]到Initiation Dispatcher的登记。当数据在网络连接上到达时,分派器回调Acceptor,后者接受网络连接,并创建HTTP Handler。于是这个HTTP Handler就登记到Reactor,以在Web服务器的单线程控制中处理在那个连接上到来的URL请求。
图8-3和图8-4显示使用反应式事件分派设计的Web服务器怎样处理多个客户。图8-3显示当客户连接到Web服务器时所采取的步骤。图8-4显示Web服务器怎样处理客户请求。图8-3的一系列步骤可被总结如下:
 
 
图8-3 客户连接到反应式Web服务器
 
 
图8-4 客户发送HTTP请求到反应式Web服务器
 
  1. Web服务器将Acceptor登记到Initiation Dispatcher,以接受新连接;
  2. Web服务器调用Initiation Dispatcher的事件循环;
  3. 客户连接到Web服务器;
  4. Initiation Dispatcher将新连接请求通知Acceptor,后者接受新连接;
  5. Acceptor创建HTTP Handler,以服务新客户;
  6. HTTP Handler将连接登记到Initiation Dispatcher,以读取客户请求数据(就是说,在连接变得“读就绪”时);
  7. HTTP Handler服务来自新客户的请求。
 
图8-4显示反应式Web服务器为服务HTTP GET请求所采取的一系列步骤。该过程描述如下:
 
  1. 客户发送HTTP GET请求;
  2. 当客户请求数据到达服务器时,Initiation Dispatcher通知HTTP Handler;
  3. 请求以非阻塞方式被读取,于是如果操作会导致调用线程阻塞,读操作就返回EWOULDBLOCK(步骤2和3将重复直到请求被完全读取);
  4. HTTP Handler解析HTTP请求;
  5. 所请求的文件从文件系统中被同步读取;
  6. 为发送文件数据(就是说,当连接变得“写就绪”时),HTTP Handler将连接登记到Initiation Dispatcher;
  7. 当TCP连接变得写就绪时,Initiation Dispatcher通知HTTP Handler;
  8. HTTP Handler以非阻塞方式将所请求文件发送给客户,于是如果操作会导致调用线程阻塞,写操作就返回EWOULDBLOCK(步骤7和8将重复直到数据被完全递送)。
 
附录A.2中有一个将反应式事件分派模型应用于Web服务器的C++代码例子。
因为Initiation Dispatcher运行在单线程中,网络I/O操作以非阻塞方式运行在Reactor的控制之下。如果当前操作的进度停止了,操作就被转手给Initiation Dispatcher,由它监控系统操作的状态。当操作可以再度前进时,适当的Event Handler会被通知。
反应式模式的主要优点是可移植性,粗粒度并发控制带来的低开销(就是说,单线程不需要同步或上下文切换),以及通过使应用逻辑与分派机制去耦合所获得的模块性。但是,该方法有以下缺点:
 
复杂的编程:如从前面的列表所看到的,程序员必须编写复杂的逻辑,以保证服务器不会在服务一个特定客户时阻塞。
 
缺乏多线程的OS支持:大多数操作系统通过select系统调用[7]来实现反应式分派模型。但是,select不允许多于一个的线程在同一个描述符集上等待。这使得反应式模型不适用于高性能应用,因为它没有有效地利用硬件的并行性。
 
可运行任务的调度:在支持占先式线程的同步多线程体系结构中,将可运行线程调度并时分(time-slice)到可用CPU上是操作系统的责任。这样的调度支持在反应式体系结构中不可用,因为在应用中只有一个线程。因此,系统的开发者必须小心地在所有连接到Web服务器的客户之间将线程分时。这只能通过执行短持续时间、非阻塞的操作来完成。
 
作为这些缺点的结果,当硬件并行可用时,反应式事件分派不是最为高效的模型。由于需要避免使用阻塞I/O,该模式还有着相对较高的编程复杂度。
 
8.2.3解决方案:通过前摄式操作实现的并发
 
当OS平台支持异步操作时,一种高效而方便的实现高性能Web服务器的方法是使用前摄式事件分派。使用前摄式事件分派模型设计的Web服务器通过一或多个线程控制来处理异步操作的完成。这样,通过集成完成事件多路分离(completion event demultiplexing)和事件处理器分派,前摄器模式简化了异步的Web服务器
异步的Web服务器将这样来利用前摄器模式:首先让Web服务器向OS发出异步操作,并将回调方法登记到Completion Dispatcher(完成分派器),后者将在操作完成时通知Web服务器。于是OS代表Web服务器执行操作,并随即在一个周知的地方将结果排队。Completion Dispatcher负责使完成通知出队,并执行适当的、含有应用特有的Web服务器代码的回调。
 
 
图8-5 客户连接到基于前摄器的Web服务器
 
 
图8-6 客户发送请求给基于前摄器的Web服务器
 
图8-5和图8-6显示使用前摄式事件分派设计的Web服务器怎样在一或多个线程中并发地处理多个客户。图8-5显示当客户连接到Web服务器时所采取的一系列步骤。
 
  1. Web服务器指示Acceptor发起异步接受;
  2. 接受器通过OS发起异步接受,将其自身作为Completion Handler和Completion Dispatcher的引用传递;并将用于在异步接受完成时通知Acceptor;
  3. Web服务器调用Completion Dispatcher的事件循环;
  4. 客户连接到Web服务器;
  5. 当异步接受操作完成时,操作系统通知Completion Dispatcher;
  6. Completion Dispatcher通知接受器;
  7. Acceptor创建HTTP Handler;
  8. HTTP Handler发起异步操作,以读取来自客户的请求数据,并将其自身作为Completion Handler和Completion Dispatcher的引用传递;并将用于在异步读取完成时通知HTTP Handler。
 
图8-6 显示前摄式Web服务器为服务HTTP GET请求所采取的步骤。这些步骤解释如下:
 
  1. 客户发送HTTP GET请求;
  2. 读取操作完成,操作系统通知Completion Dispatcher;
  3. Completion Dispatcher通知HTTP Handler(步骤2和3将重复直到整个请求被接收);
  4. HTTP Handler解析请求;
  5. HTTP Handler同步地读取所请求的文件;
  6. HTTP Handler发起异步操作,以把文件数据写到客户连接,并将其自身作为Completion Handler和Completion Dispatcher的引用传递;并将用于在异步写入完成时通知HTTP Handler。
  7. 当写操作完成时,操作系统通知Completion Dispatcher;
  8. 随后Completion Dispatcher通知Completion Handler(步骤6-8将重复直到文件被完全递送)。
 
8.8中有一个将前摄式事件分派模型应用于Web服务器的C++代码例子。
使用前摄器模式的主要优点是可以启动多个并发操作,并可并行运行,而不要求应用必须拥有多个线程。操作被应用异步地启动,它们在OS的I/O子系统中运行直到完成。发起操作的线程现在可以服务另外的请求了。
例如,在上面的例子中,Completion Dispatcher可以是单线程的。当HTTP请求到达时,单个Completion Dispatcher线程解析请求,读取文件,并发送响应给客户。因为响应是被异步发送的,多个响应就有可能同时被发送。而且,同步的文件读取可以被异步的文件读取取代,以进一步增加并发的潜力。如果文件读取是被异步完成的,HTTP Handler所执行的唯一的同步操作就只剩下了HTTP协议请求解析。
前摄式模型的主要缺点是编程逻辑至少和反应式模型一样复杂。而且,前摄器模式可能会难以调试,因为异步操作常常有着不可预测和不可重复的执行序列,这就使分析和调试复杂化了。8.7描述怎样应用其他模式(比如异步完成令牌[8])来简化异步应用编程模型。

TAG: 技术 前摄器 分派处理器

41/41234>
 

评分:0

我来说两句

seccode