gpt4 book ai didi

node.js - 具有多个并发请求的Node.js服务器,它如何工作?

转载 作者:行者123 更新时间:2023-12-03 13:43:33 25 4
gpt4 key购买 nike

我知道node.js是一个单线程,异步,无阻塞的I/O。我已经读了很多。例如,PHP每个请求使用一个线程,但是节点仅对所有线程使用一个线程。

假设有三个请求a,b,c同时到达node.js服务器。这些请求中的三个要求进行较大的阻止操作,例如,它们都希望读取相同的大文件。

然后,如何将请求排入队列,将按什么顺序执行阻塞操作,以及按什么顺序分派(dispatch)响应?当然要用多少个线程?

请告诉我三个请求从请求到响应的顺序。

最佳答案

这是您的三个请求的一系列事件的描述:

  • 三个请求发送到node.js Web服务器。
  • 无论哪个请求在其他两个请求之前到达的一部分都会触发Web服务器请求处理程序,它将开始执行。
  • 其他两个请求进入node.js事件队列,等待轮到他们。从技术上讲,是否将等待的请求排队在传入的TCP级别上,还是将它排队在node.js内部(我实际上不知道),这完全取决于node.js实现的内部,但是出于讨论的目的,所有重要的是,传入事件已排队,直到第一个请求停止运行时才触发。
  • 第一个请求处理程序将执行,直到执行异步操作(例如读取文件),然后再执行其他操作,直到异步操作完成。
  • 此时,将启动异步文件I/O操作,并且原始请求处理程序将返回(通过此时的操作来完成)。
  • 由于第一个请求(正在等待文件I/O)暂时已返回,因此node.js引擎现在可以将下一个事件从事件队列中拉出并启动它。这是到达服务器的第二个请求。它将在第一个请求时经历相同的过程,并将一直运行直到无其他事情为止(并且还在等待文件I/O)。
  • 当第二个请求返回系统时(因为它正在等待文件I/O),则第三个请求可以开始运行。它将遵循与前两个相同的路径。
  • 当第三个请求现在也正在等待I/O并返回系统时,node.js可以自由地将下一个事件从事件队列中拉出。
  • 此时,所有三个请求处理程序都同时处于“运行中”状态。实际上只有一次可以运行,但是所有进程都可以同时运行。
  • 事件队列中的下一个事件可能是其他事件或其他请求,也可能是前三个文件I/O操作之一的完成。队列中下一个事件将开始执行。假设这是第一个请求的文件I/O操作。此时,它将调用与该第一个请求的文件I/O操作关联的完成回调,并且该第一个请求开始处理文件I/O结果。然后,该代码将继续运行,直到完成整个请求并返回,或者开始其他异步操作(如更多文件I/O)并返回为止。
  • 最终,第二个请求的文件I/O将准备就绪,该事件将从事件队列中拉出。
  • 然后,对第三个请求相同,最终所有三个请求都将完成。

  • 因此,即使实际上实际上只有一个请求同时在执行,多个请求也可以同时处于“处理中”或“运行中”状态。有时这称为协作多任务,而不是通过具有多个 native 线程的“抢先式”多任务,系统可以随时在这些线程之间自由切换,给定的Javascript线程运行直到返回系统,然后再返回,直到那时,另一段Javascript才能开始运行。因为一段Javascript可以启动非阻塞异步操作,所以Javascript线程可以在其异步操作仍处于挂起状态时返回到系统(使其他Javascript片段可以运行)。这些操作完成后,它们会将事件发布到事件队列中,而当其他Javascript完成并且该事件到达队列顶部时,它将运行。

    单线程

    这里的关键点是,给定的Javascript线程将一直运行,直到它返回系统为止。如果在执行过程中启动了一些异步操作(例如文件I/O或网络连接),那么当这些事件结束时,它们会将一个事件放入事件队列中,并且当JS引擎完成运行任何事件之前,它,该事件将得到处理,并将导致调用回调,并且该回调将轮流执行。

    与多线程模型相比,这种单线程性质极大地简化了并发的处理方式。在每个请求都启动其自己的线程的完全多线程环境中,任何希望共享的数据,甚至是一个简单的变量,都必须遵守竞争条件,并且必须使用互斥体进行保护,然后任何人都可以读取它。

    在Javascript中,因为没有同时执行多个请求,所以不需要简单的共享变量访问就可以使用互斥锁。从定义上看,一段Javascript正在读取一个变量,此时没有其他Javascript在运行(单线程)。

    Node.js确实使用线程

    注意的一种技术区别是,只有Javascript的执行是单线程的。 node.js内部构件确实将线程本身用于某些方面。例如,异步文件I/O实际上使用 native 线程。网络I/O实际上并不使用线程(它使用 native 事件驱动的网络)。

    但是,在node.js内部使用线程不会直接影响Javascript执行。一次只执行一个Java线程。

    比赛条件

    启动异步操作时,状态仍可能处于被修改的竞争状态,但这是一种方式,比多线程环境中的方式少见,并且更容易识别和保护这些情况。作为可能存在的竞争条件的示例,我有一个简单的服务器,该服务器使用间隔计时器每10秒从多个温度探测器获取读数。它从所有这些温度读数中收集数据,并且每小时将其写出到磁盘中。它使用异步I/O将数据写入磁盘。但是,由于使用了许多不同的异步文件I/O操作将数据写入磁盘,因此间隔计时器可能会在某些异步文件I/O操作之间触发,从而导致服务器所在的数据写到要修改的磁盘的中间。这很不好,可能导致写入不一致的数据。在一个简单的世界中,可以通过在开始将所有数据复制到磁盘之前对其进行复制来避免这种情况,因此,如果在将数据写入磁盘时出现新的温度读数,则复制不会受到影响,并且代码仍会将一致的数据集写入磁盘。但是,对于此服务器,数据可能很大,而服务器上的内存却很小(这是Raspberry Pi服务器),因此在内存中复制所有数据是不切实际的。

    因此,通过在将数据写入磁盘的过程中设置一个标志,然后在将数据写入磁盘的过程中清除该标志,可以解决该问题。如果在设置此标志时触发间隔计时器,则会将新数据放入单独的队列中,并且不会修改正在写入磁盘的核心数据。将数据写入磁盘后,它将检查队列并将发现的任何温度数据添加到内存中的温度数据中。保留了正在写入磁盘的过程的完整性。每当此“竞赛条件”被击中并且由于该数据而使数据排队时,我的服务器都会记录一个事件。而且,瞧,它确实每隔一段时间就会发生一次,并且保存数据完整性的代码也起作用了。

    关于node.js - 具有多个并发请求的Node.js服务器,它如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36542404/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com