【问题标题】:How does event-driven programming help a webserver that only does IO?事件驱动编程如何帮助只做 IO 的网络服务器?
【发布时间】:2018-09-12 22:45:20
【问题描述】:

我正在为我们的新后端项目考虑一些框架/编程方法。它涉及聚合下游服务的 BackendForFrontend 实现。为简单起见,以下是它所经历的步骤:

  1. 请求进入网络服务器
  2. 网络服务器发出下游请求
  3. 下游请求返回结果
  4. 网络服务器返回请求

事件驱动编程比“常规的”线程每个请求处理更好吗?一些网站试图解释,通常归结为这样的:

第二种解决方案是非阻塞调用。调用者不等待答案,而是继续执行,但提供了一个回调,一旦数据到达就会执行。

我不明白的是:我们需要一个线程/处理程序来等待这些数据,对吧?事件处理程序可以继续,这很好,但我们仍然需要(在此示例中)每个请求的线程/处理程序来等待每个下游请求,对吧?

考虑这个例子:下游请求需要 n 秒才能返回。在这 n 秒内,有 r 个请求进来。在每个请求的线程中,我们需要 r 个线程:每个请求一个。经过 n 秒后,第一个线程完成处理并可用于新请求。

在实现事件驱动设计时,我们需要 r+1 个线程:一个事件循环和 r 个处理程序。每个处理程序接受一个请求,执行它,并在完成后调用回调。

那么这对改善有什么好处呢?

【问题讨论】:

  • 我刚刚想到的:如果我们有一个可以在同一个线程上处理多个请求的处理程序,那么好处是显而易见的:我们只需要一个(或几个冗余)处理程序,从而大大减少了数量所需的线程数。但这真的不可能,对吧?
  • 为什么不呢? “处理程序”只是一个数据结构,它记住上游和下游每个连接(套接字号、地址、cookie 等)的状态并维护它们之间的关联,加上一些知道如何处理下一个输入的代码,实际上, 在您的状态机上“转动曲柄”。每个连接都有自己独立的数据结构/当前状态。在单个线程中可以处理多少个请求没有硬性限制。
  • 你能详细说明一下吗?这样的实现怎么叫?我尝试对此进行研究,但找不到任何东西,但也许我的关键字(“同一线程上的多个 HTTP 请求”)不正确
  • 据我了解,您总是需要一个线程池来执行并行请求,因为您必须始终以同步方式执行请求。是的,您可以围绕此构建一个异步 API,但实际上执行请求需要一个等待线程(再次,据我了解)
  • 没有。套接字接收(当数据已经可用时)只是将字节从内核缓冲区复制到用户空间缓冲区。发送是相反的:从用户空间复制到内核(假设内核缓冲区中有空间)。因此,这些操作“同步的”,因为当它们正在进行时,您的线程中没有发生任何其他事情,但它们几乎是瞬间完成的。 selectpoll 和类似机制允许您等待多个套接字中的任何一个变为“可读”或“可写”。

标签: multithreading webserver event-driven event-driven-design


【解决方案1】:

我不明白的是:我们需要一个线程/处理程序来等待这些数据, 对吧?

不是真的。 NIO 背后的理念是没有线程被阻塞。

这很有趣,因为操作系统已经以非阻塞方式工作。我们的编程语言是以阻塞方式建模的。

例如,假设您有一台具有单个 CPU 的计算机。您所做的任何 I/O 操作都会比 CPU 慢几个数量级,对吧?假设您要读取文件。你认为 CPU 会呆在那里,空闲,什么都不做,而磁盘头去获取几个字节并将它们放入磁盘缓冲区?显然不是。操作系统将注册一个中断(即回调),同时将宝贵的 CPU 用于其他事情。当磁头成功读取了几个字节并使其可供使用时,将触发中断,然后操作系统将关注它,恢复先前的进程块并分配一些 CPU 时间来处理可用数据。

因此,在这种情况下,CPU 就像您的应用程序中的一个线程。它永远不会被阻塞。它总是在做一些 CPU 密集型的事情。

NIO 编程背后的想法是相同的。在您公开的情况下,假设您的 HTTP 服务器有一个线程。当您收到来自客户端的请求时,您需要发出上游请求(代表 I/O)。所以 NIO 框架在这里要做的就是发出请求并在响应可用时注册回调。

在此之后,您有价值的单线程立即被释放以处理另一个请求,该请求将注册另一个回调,依此类推。

当回调解决时,它会被自动安排到你的单线程处理。

因此,该线程作为一个事件循环工作,您应该在其中只安排 CPU 绑定的东西。每次需要进行 I/O 时,都是以非阻塞方式完成的,当 I/O 完成时,一些 CPU 绑定的回调会被放入事件循环中以处理响应。

这是一个强大的概念,因为您可以使用非常少量的线程来处理数千个请求,因此您可以更轻松地进行扩展。事半功倍。

此功能是Node.js 的主要卖点之一,也是即使使用单线程也可以用于开发后端应用程序的原因。

同样,这也是 NettyRxJavaReactive Streams InitiativeProject Reactor 等框架激增的原因。他们都在寻求推广这种优化和编程模型。

还有一个有趣的新框架运动,利用这些强大的功能并试图相互竞争或互补。我说的是Vert.xRatpack 等有趣的项目。而且我很确定还有更多其他语言可供选择。

【讨论】:

    【解决方案2】:
    猜你喜欢
    • 2023-03-29
    • 1970-01-01
    • 2012-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-11
    相关资源
    最近更新 更多