Multithreading 事件驱动编程如何帮助只执行IO的Web服务器?

Multithreading 事件驱动编程如何帮助只执行IO的Web服务器?,multithreading,webserver,event-driven,event-driven-design,Multithreading,Webserver,Event Driven,Event Driven Design,我正在为我们的新后端项目考虑一些框架/编程方法。它涉及到后端到前端的实现,它聚合了下游服务。为简单起见,以下是它所经历的步骤: 请求进入Web服务器 Web服务器发出下游请求 下游请求返回结果 Web服务器返回请求 事件驱动编程如何比“常规”线程每请求处理更好?一些网站试图解释,通常可以归结为以下几点: 第二种解决方案是非阻塞调用。调用者不等待应答,而是继续执行,但提供一个回调,一旦数据到达就会执行 我不明白的是:我们需要一个线程/处理程序来等待这些数据,对吗?事件处理程序可以继续,这很好,但我

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

  • 请求进入Web服务器
  • Web服务器发出下游请求
  • 下游请求返回结果
  • Web服务器返回请求
  • 事件驱动编程如何比“常规”线程每请求处理更好?一些网站试图解释,通常可以归结为以下几点:

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

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

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

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

    那么这是如何改善情况的呢

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

    不是真的。NIO背后的思想是没有线程被阻塞

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

    例如,假设您有一台只有一个CPU的计算机。您执行的任何I/O操作都将比CPU慢几个数量级,对吗?。假设您要读取一个文件。你认为CPU会呆在那里,空闲,什么也不做,而磁头会去提取一些字节并将它们放入磁盘缓冲区吗?显然不是。操作系统将注册一个中断(即回调),同时将使用有价值的CPU进行其他操作。当磁头已设法读取几个字节并使其可供使用时,将触发一个中断,然后操作系统将注意它,恢复以前的进程块并分配一些CPU时间来处理可用数据

    因此,在本例中,CPU就像应用程序中的线程。它从不被阻塞。它总是在做一些CPU限制的事情

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

    紧接着,您宝贵的单个线程被释放,以处理另一个请求,该请求将注册另一个回调,等等

    当回调解析时,它将被自动安排由单个线程处理

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

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

    此功能是的主要卖点之一,也是为什么即使使用单个线程也可以用来开发后端应用程序的原因

    同样,这也是像、和这样的框架激增的原因。他们都在寻求推广这种类型的优化和编程模型


    还有一种有趣的新框架运动利用了这种强大的功能,并试图相互竞争或互补。我说的是像和这样有趣的项目。我敢肯定,对于其他语言来说,还有更多的方法。

    非阻塞范式的整个思想是通过这个叫做 “事件循环”

    有趣的参考资料:


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