来自维基百科Reactor Pattern文章:
反应器设计模式是一种事件处理模式,用于通过一个或多个输入同时向服务处理程序传递服务请求。
它命名了一些例子,例如nodejs
、twisted
和eventmachine
但我理解上述内容是流行的事件驱动框架,因此它们也是反应器模式框架吗?
如何区分这两者?或者它们是相同的吗?
来自维基百科Reactor Pattern文章:
反应器设计模式是一种事件处理模式,用于通过一个或多个输入同时向服务处理程序传递服务请求。
它命名了一些例子,例如nodejs
、twisted
和eventmachine
但我理解上述内容是流行的事件驱动框架,因此它们也是反应器模式框架吗?
如何区分这两者?或者它们是相同的吗?
反应器模式比“事件驱动编程”更具体。它是在进行事件驱动编程时使用的一种特定实现技术。但是,在典型对话中很少准确使用这个术语,因此您在使用它并期望您的听众理解时应该小心,当您遇到其使用时,您也应该小心如何解释这个术语。
观察反应器模式的一种方式是将其视为与“非阻塞”操作的概念密切相关。当某些操作可以在没有阻塞的情况下完成时,反应器会发送通知。例如,select(2)
可以用于使用标准 BSD 套接字 API (recv(2)
、send(2)
等) 实现用于从套接字读取和写入的反应器模式。 select
将告诉您什么时候可以立即从套接字接收字节——例如,因为这些字节在该套接字的内核接收缓冲区中存在。
考虑这些思想时,您可能还想考虑另一种模式,即 proactor 模式。与反应器模式相比,proactor 模式会使操作启动,无论它们是否能够立即完成,都会异步执行,并安排通知其完成。
Windows I/O 完成端口 (IOCP) API 是一个例子,可以看到其中的 proactor 模式。在使用 IOCP 对套接字进行发送时,无论该套接字的内核发送缓冲区中是否有空间,发送操作都会启动。发送操作继续进行(可能是在另一个线程中,例如内核中的线程),而WSASend
调用会立即完成。当发送实际完成时(这意味着被发送的字节已被复制到该套接字的内核发送缓冲区中),将调用传递给 WSASend
调用的回调函数(在应用程序中的新线程中)。
这种启动操作并在其完成时得到通知的方法是异步操作的核心思想。与非阻塞操作相比,非阻塞操作需要在尝试执行操作之前等待操作可以立即完成。
这两种方法都可用于事件驱动编程。使用反应器模式,程序等待(例如)套接字可读事件,然后从中读取数据。使用proactor模式,程序则等待套接字读取完成事件。
严格来说,Twisted误用了“反应器”这个术语。基于select(2)
(twisted.internet.selectreactor
)的Twisted反应器使用非阻塞I/O实现,非常类似于反应器。但是,它向应用程序代码公开的接口是异步的,使其更像proactor。Twisted还有一个基于IOCP的反应器。该反应器公开相同的异步应用程序接口并且使用类似proactor的IOCP API。这种混合方法因平台而异,其细节不同,使“反应器”或“proactor”这两个术语都不太准确,但由于twisted.internet.reactor
公开的API基本上完全是异步的而不是非阻塞的,因此“proactor”可能是更好的名称选择。
我认为将“非阻塞”和“异步”分开是不正确的,因为“异步”的主要含义是“非阻塞”。反应器模式是关于异步调用(因此是非阻塞的),但是同步(阻塞)处理这些调用。Proactor是关于异步(非阻塞)调用和异步(非阻塞)处理这些调用。
为了处理TCP连接,有两种竞争的Web架构,分别是基于线程的架构和事件驱动的架构。
实现多线程服务器的最古老方式是采用“每个连接一个线程”的方法。为了控制和限制运行线程的数量,可以使用单个调度程序线程以及有界阻塞队列和线程池。
调度程序在TCP套接字上阻塞以获取新连接,并将它们提供给有界阻塞队列。超过队列限制的TCP连接将被丢弃,允许已接受的连接以期望和可预测的延迟运行。
将线程从连接中分离出来,事件驱动架构只允许将线程用于特定处理程序的事件。
这种创造性的概念使得反应器模式得以展示。基于这种架构构建的系统由事件创建者和事件消费者组成。
反应器模式是处理TCP连接的事件驱动架构的最流行实现技术。简单来说,它使用单线程事件循环,在事件上阻塞并将这些事件分派到相应的处理程序。
只要为事件注册了处理程序,其他线程就无需在I/O上阻塞。对于TCP连接,我们可以轻松地将事件引用到这些实例:已连接、输入准备就绪、输出准备就绪、超时和已断开。
反应器模式将模块化的应用级代码与可重用的反应器实现解耦。为了实现这一点,反应器模式的架构由两个重要的参与者组成——反应器和处理程序。
反应器在单独的线程中运行,并通过将工作分派给适当注册的处理程序来响应I/O事件,如已连接、输入准备就绪、输出准备就绪、超时和已断开。
处理程序执行实际工作或需要完成的I/O事件响应。反应器通过分派适当的处理程序响应I/O事件。
《程序设计的模式语言》是Jim Coplien和Douglas C. Schmidt于1995年出版的一本详细介绍反应器模式的书籍。
select
和 从套接字接收字节 来解释反应器模式,那么你应该使用它们来解释 proactor 模式。否则,这会非常令人困惑,因为情景中有多个变化,对比变得太模糊了;实际上有两种不同的情景。你应该只使用一种! - Nawaz