事件驱动模型和反应器模式有啥区别? [关闭]
Posted
技术标签:
【中文标题】事件驱动模型和反应器模式有啥区别? [关闭]【英文标题】:What is the difference between event driven model and reactor pattern? [closed]事件驱动模型和反应器模式有什么区别? [关闭] 【发布时间】:2012-02-26 15:21:47 【问题描述】:来自***Reactor Pattern 文章:
反应器设计模式是一种事件处理模式,用于处理通过一个或多个输入同时传递给服务处理程序的服务请求。
它列举了几个例子,例如nodejs
、twisted
、eventmachine
但我理解上面是流行的事件驱动框架,所以让它们也成为反应器模式框架?
如何区分这两者?还是一样?
【问题讨论】:
【参考方案1】:反应器模式比“事件驱动编程”更具体。它是在进行事件驱动编程时使用的一种特定实现技术。但是,该术语在典型对话中的使用并不准确,因此您应该小心使用它并期望您的听众理解您,并且在遇到该术语时您应该小心如何解释它。
查看反应器模式的一种方法是将其与“非阻塞”操作的概念密切相关。当某些操作可以在没有阻塞的情况下完成时,反应器会发出通知。例如,select(2)
可用于实现反应器模式,以使用标准 BSD 套接字 API(recv(2)
、send(2)
等)读取和写入套接字。 select
会告诉您何时可以立即从套接字接收字节 - 因为字节存在于该套接字的内核接收缓冲区中。
在考虑这些想法时,您可能需要考虑的另一种模式是 proactor 模式。与反应器模式相比,前摄器模式让操作开始,无论它们是否可以立即完成,它们是否异步执行,然后安排发送有关它们完成的通知。
Windows I/O 完成端口 (IOCP) API 是可以看到 proactor 模式的一个示例。当使用 IOCP 在套接字上执行发送时,无论内核发送缓冲区中是否有该套接字的空间,都会启动发送操作。发送操作继续(在另一个线程中,可能是内核中的一个线程),而WSASend
调用立即完成。当发送 实际上 完成时(仅意味着正在发送的字节已被复制到该套接字的内核发送缓冲区中),将调用提供给 WSASend
调用的回调函数(在新线程中)在应用程序中)。
这种启动操作并在操作完成时收到通知的方法是异步操作的核心。将其与非阻塞操作进行比较,在这些操作中,您要等到操作可以立即完成后再尝试执行它。
这两种方法都可以用于事件驱动编程。使用反应器模式,程序等待(例如)套接字的 事件 可读,然后从中读取。使用前摄器模式,程序改为等待套接字读取完成的事件。
严格来说,Twisted 误用了 reactor 一词。基于select(2)
(twisted.internet.selectreactor
) 的 Twisted reactor 使用非阻塞 I/O 实现,非常类似于 reactor。但是,它向应用程序代码公开的接口是异步的,使其更像是前摄器。 Twisted 还有一个基于 IOCP 的反应器。该反应器公开了相同的异步面向应用程序的 API并使用类似于 proactor 的 IOCP API。这种混合方法在细节上因平台而异,使得术语“反应器”和“前摄器”都不是特别准确,但由于twisted.internet.reactor
公开的 API 基本上是完全异步的而不是非阻塞的,前摄器 可能是一个更好的名称选择。
【讨论】:
1.我可以这样说吗:反应堆模式是一种将事件异步排队,但同步解复用和分派它们的模式;而 Proactor 模式将它们全部异步排队、解复用和分派? 2. 考虑到 select(2) API,在使用事件编程时,像 libevent 这样的现代库有什么好处(我知道与这个问题无关,但作为该领域的专家......)谢谢。跨度> re 1:这就是***页面的说法,所以我犹豫只说“不” :) 然而,作为一名从业者,这不是我在真实世界。由于这些术语相当晦涩,并且在使用它们时经常被误用,我认为您可以安全地说,但也可以安全地说其他东西(例如反应器->非阻塞,前摄器->异步)。也许两者相距不远(你可以想象“同步”的意思是“同步、非阻塞”——毕竟“同步、阻塞”会干扰反应器的进一步运行) re 2: select(2) 级别很低,很难使用。对于大量事件源来说,它也是低效的。现代平台已经超越了它,提供了等效但更高效的 API(/dev/poll、epoll、kqueue 等)。 libevent(或 Twisted)的一个优点是对所有这些不同机制的抽象,因此可以将应用程序写入统一的 API,同时仍然受益于运行时平台上最有效的 API。加上协议实现、用于管理异步的高级 API 等形式的明显附加功能。 关于 select(2) 与 epoll(4) 的比较,请参阅***.com/questions/2032598/… 如果你用select
和receiving bytes从一个socket来解释reactor模式,那么你应该用它们来解释proactor模式。否则,它会非常混乱,因为对比变得过于模糊,因为场景中不止一件事发生了变化;实际上有两种不同的情况。你应该只使用一个!【参考方案2】:
我认为这种“非阻塞”和“异步”的分离是错误的,因为“异步”的主要含义是“非阻塞”。反应器模式是关于异步(非阻塞)调用,但对这些调用进行同步(阻塞)处理。 Proactor 是关于异步(非阻塞)调用和这些调用的异步(非阻塞)处理。
【讨论】:
【参考方案3】:为了处理 TCP 连接,有两种相互竞争的 Web 架构,即基于线程的架构和事件驱动的架构。
基于线程的架构
实现多线程服务器的最古老方法是遵循“每个连接线程”方法。为了控制和限制运行线程的数量,可以使用单个调度程序线程以及有界阻塞队列和线程池。
调度程序在 TCP 套接字上阻塞新连接并将它们提供给有界阻塞队列。超出队列边界的 TCP 连接将被丢弃,允许接受的连接以理想且可预测的延迟运行。
事件驱动架构
将线程与连接分离,事件驱动架构只允许线程用于特定处理程序上的事件。
这个创意概念让 Reactor Pattern 脱颖而出并大显身手。基于此架构构建的系统由事件创建者和事件消费者组成。
反应堆模式
反应器模式是用于 TCP 连接处理的事件驱动架构最流行的实现技术。简单来说,它使用单线程事件循环,阻塞事件并将这些事件分派给相应的处理程序。
只要注册了事件处理程序来处理它们,其他线程就不需要阻塞 I/O。考虑 TCP 连接,我们可以轻松地将事件引用到这些实例:已连接、输入就绪、输出就绪、超时和断开连接。
反应器模式将模块化应用程序级代码与可重用反应器实现分离。为了实现这一点,reactor 模式的架构由两个重要的参与者组成 —— Reactor 和 Handler。
反应堆
Reactor 在单独的线程中运行,它通过将工作分派给适当的注册处理程序来对 I/O 事件(例如已连接、输入就绪、输出就绪、超时和断开连接)做出反应。
处理程序
处理程序执行实际工作或需要通过 I/O 事件完成的响应。 Reactor 通过调度适当的处理程序来响应 I/O 事件。
Jim Coplien 和 Douglas C. Schmidt 于 1995 年出版的“程序设计的模式语言”是详细解释反应堆模式的书籍之一。
【讨论】:
以上是关于事件驱动模型和反应器模式有啥区别? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章