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

2024-02-21

我知道node.js是单线程、异步、非阻塞I/O。我读过很多相关内容。例如,PHP 每个请求使用一个线程,但 Node 只对所有请求使用一个线程,就像这样。

假设有三个请求a、b、c同时到达node.js服务器。其中三个请求需要大型阻塞操作,例如它们都想要读取相同的大文件。

那么请求是如何排队的,阻塞操作会以什么顺序执行,响应又以什么顺序发送呢?当然使用多少个线程?

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


以下是针对您的三个请求的一系列事件的描述:

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

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

单线程

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

与多线程模型相比,这种单线程特性极大地简化了并发处理方式。在完全多线程的环境中,每个请求都启动自己的线程,因此任何希望共享的数据(即使是简单的变量)也会受到竞争条件的影响,并且必须使用互斥体进行保护,然后才能让任何人读取它。

在Javascript中,由于不存在多个请求的并发执行,因此简单的共享变量访问不需要互斥锁。根据定义,当一段 Javascript 正在读取变量时,此时没有其他 Javascript 正在运行(单线程)。

Node.js 确实使用线程

值得注意的一项技术区别是,只有 Javascript 的执行是单线程的。 Node.js 内部确实使用线程本身来完成某些事情。例如,异步文件 I/O 实际上使用本机线程。网络 I/O 实际上并不使用线程(它使用本机事件驱动的网络)。

但是,在 Node.js 内部使用线程不会直接影响 Javascript 的执行。一次仍然只有一个 Javascript 线程在执行。

竞赛条件

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

因此,通过在数据写入磁盘的过程中设置一个标志,然后在数据写入磁盘完成后清除该标志来解决该问题。如果在设置此标志时触发间隔计时器,则新数据将放入单独的队列中,并且正在写入磁盘的核心数据不会被修改。当数据写入磁盘后,它会检查队列,然后将其中找到的任何温度数据添加到内存中的温度数据中。写入磁盘过程中的内容的完整性得以保留。每当遇到这种“竞争条件”并且数据因此而排队时,我的服务器都会记录一个事件。而且,你瞧,这种情况确实每隔一段时间就会发生一次,并且保护数据完整性的代码可以正常工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Node.js 服务器有多个并发请求,它是如何工作的? 的相关文章

  • 从 MongoDB+Node.js 获取数据到客户端 JavaScript

    如何使用 Node js 连接 MongoDB 然后将结果传递给客户端 JavaScript 并以 HTML 形式显示 var http require http var URL require url var Db require mon
  • npm install 冻结并显示 IdealTree:chatting: sill IdealTree buildDeps

    当我安装任何东西时 npm 冻结了 即使删除 package lock json 也没有任何变化 这里有一个类似的问题 https stackoverflow com questions 50522376 npm install hangs
  • Node Js:Redis 作业在完成其任务后未完成

    希望你们做得很好 我在我的 Nodejs 项目中实现了 BullMQ Bull 的下一个主要版本 来安排发送电子邮件的作业 例如 发送忘记密码请求的电子邮件 所以 我编写了如下所示的代码 用户服务 await resetPasswordJo
  • 基于 NodeJS 的Radio(不带 ShoutCast)

    我喜欢创建一个基于 NodeJS 的广播电台not使用ShoutCast 基于 NodeJS 的播放列表 目前我已成功将音频文件发送到浏览器 但我不知道如何创建服务器端播放列表它会持续 播放 当前歌曲 并在播放结束后重新开始播放 这就是我目
  • nodejs googleapis,authClient.request 不是函数

    我正在像这样的一个函数中创建一个 oauth2client 并返回它 实际上 我确实传递了客户端 ID 秘密 重定向 URL 和凭据 据我检查 这些都是正确的 var OAuth2 google auth OAuth2 var oauth2
  • 如何将子集合添加到 Firestore 中的文档? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 没有关于如何在Firestore中的文档中添加子集合的文档 那么如何使用Web应用程序添加子集合 我尝试了这个但没有成功 如何使用代码
  • Nodemon - 使用配置文件指定扩展监视列表

    有没有办法使用配置文件而不是命令行来指定监视列表 Nodemon 文档中的命令行方法 我尝试使用nodemon json配置文件包含以下内容 ext js json hbs html 返回 扩展名匹配 错误 然后我尝试将配置添加到packa
  • 如何从 docker 容器运行 webpack 构建?

    我正在制作的应用程序是用 ES6 编写的 其他好东西是由 Docker 容器内的 webpack 转译的 目前 一切工作从创建内部目录 安装依赖项到创建编译的捆绑文件 当运行容器时 它说 dist bundle js 不存在 除非我在主机目
  • 使用 Sequelize 计算关联条目数

    我有两张桌子 locations and sensors 每个条目在sensors有一个外键指向locations 使用 Sequelize 如何获取所有条目locations以及条目总数sensors与每个条目相关联locations R
  • 将 AngularJS 应用程序部署到普通 Apache HTTP 服务器是一种常见的选择吗?

    我很好奇 AngularJS 应用程序通常部署到什么样的服务器上 Google 没有给出令人满意的答案 特别是 在我看来 AngularJS 应用程序只是静态文件的集合 因此在生产中将这样的应用程序部署到普通 Apache HTTP 服务器
  • 使用node.js/Express从HTTP重定向到HTTPS

    有什么方法可以更改我的 Web 应用程序以侦听 HTTPS 而不是 HTTP 我正在使用node js express 我需要它来侦听 HTTPS 因为我正在使用地理定位 而 Chrome 不再支持地理定位 除非从 HTTPS 等安全上下文
  • 如何使用 Node.js 在 Firebase 中注册用户?

    PROBLEM 0 用户是在 Firebase 的身份验证系统中创建的 我在 身份验证 选项卡中看到它 1 但没有对数据库进行任何更改 2 页面似乎无限加载 3 控制台仅记录 Started 1 CODE router post regis
  • npm 脚本:node-sass 不监视部分 sass 文件

    我有这个项目结构 src assets css sass main scss variables scss 我正在尝试编写一个 npm 脚本 该脚本将监视我的所有 scss 文件 包括部分文件 中的更改 然后仅编译我的 main scss
  • JavaScript 中的 Promise.all:如何获取所有 Promise 的解析值?

    我编写了以下node js文件 var csv require csv parser var fs require fs var Promise require bluebird var filename devices csv var d
  • 嵌套对象的 AJV 模式验证

    函数返回的对象看起来像这样 answer vehicle type 1 message Car model VW color red 答案 对象始终存在 其他字段基于 vehicle type E g 如果vehicle type 1 则有
  • Node.js 解析路由的最小函数

    我有一个 Node js Express 应用程序正在运行 它接收如下路由 app get resource res someFunction app get foo bar id someOtherFunction 这很棒并且工作正常 我
  • 我可以在谷歌云功能上托管nodejs GRPC服务器吗?

    我有一个在 AWS 实例上运行的 Nodejs GRPC 服务器 并且想迁移到谷歌云功能 这可能吗 我的无服务器选项有哪些 对的 这是可能的 to use 云功能 https cloud google com functions 为您gRP
  • 如何使用 exceljs 读取 .xls 文件?

    我无法使用 exceljs 库读取 xls 文件 我还尝试使用 fs 更改 xlsx 中的文件后进行读取 但仍然无法从该文件中读取数据 有没有办法使用 exceljs 读取 xls 文件 虽然它的文档没有明确说明 exceljs仅支持 XL
  • Node 和 General 中的 MVC:模型如何与视图绑定?

    我从 node js 开始 正在制作一个简单的 MVC 框架 到目前为止 我已经有一个前端控制器 或 调度程序 如果你愿意的话 可以工作 路由通过调度程序配置模块进行 如图所示 我的问题在最后 紧接代码之后 另外 这是学习node的练习 请
  • 我想使用 Sequelize 将 MySQL 中的对象数组存储在单个列中

    之前我正在寻找如何使用 Sequelize 在 MySQL 中插入对象数组 然后我找到了一种直接插入数组的解决方案 例如 1 2 在单列中 insert into TABLE NAME id marks VALUES 21 1 2 但我正在

随机推荐

  • XAudio2 - 更改频率时播放生成的正弦声音

    我想开发一个应用程序来匹配您的耳鸣频率 播放频率 用户通过按加号或减号按钮来减少或增加频率 参见部分代码 基于 stackoverflow 的一些编码 谢谢 public static short BufferSamples new sho
  • Scala Play Json 读取

    我有一个示例代码如下 import play api libs json import play api libs functional syntax import play api data validation ValidationEr
  • 我应该使用什么 shebang 来始终指向 python3?

    我有一个使用 shebang 的脚本 usr bin env python 它在 Python 3 是唯一可用版本的计算机上运行良好 但在同时具有 Python 2 和 Python 3 的计算机上 它使用 Python 2 运行脚本 如果
  • 如何检测 TabBarView 刚刚被拖动?

    TabBar 小部件有一个 onTap 回调 可以检测用户何时刚刚按下了选项卡 这很有用 因此我们可以准备新的 tabView 来显示一些动态数据 TabBar 小部件还具有拖动功能 允许更改显示的 tabView 与点击另一个选项卡的结果
  • 当我将鼠标悬停在其上方大小发生变化的元素上时,如何防止 div 移动

    http bit ly 1fVGrBT http bit ly 1fVGrBT 这是我的网站 当您将鼠标悬停在 Problem 上并移开时 其下方的 div 会被上下推动 解决方案也会发生同样的情况 有什么想法或建议如何防止它移动吗 我认为
  • 采购后清理全局环境:如何在 R 中删除某种类型的对象

    我读到了一个公共数据集 该数据集在构建最终数据帧的过程中创建了数十个临时向量 由于该数据框将作为更大流程的一部分进行分析 因此我计划source使用创建数据帧的 R 脚本 但不想让自己或未来的用户面临混乱的全局环境 我知道我可以使用ls列出
  • 具有多个字段的对象的Java比较器[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有一个对象Collection有 5 个字段 id entityType entityId brandId productId 要对一个
  • 如何拦截 .NET 程序中对文件的访问

    我需要在系统尝试访问文件时进行拦截 并在其发生之前执行某些操作 您可以使用FileSystemWatcher http msdn microsoft com en us library system io filesystemwatcher
  • 使用 python-requests 上传文件 - UnicodeDecodeError

    我正在尝试使用 python requests 上传文件 with open file zip rb as fff up requests post url files file fff 并得到 UnicodeDecodeError asc
  • TADOStoredProc 和 SQL Server 存储过程,参数作为默认值

    我正在使用 Delphi 7 和 SQL Server 2008 我创建了一个虚拟表和虚拟存储过程 如下所示 CREATE TABLE dbo Persons P ID int IDENTITY 1 1 NOT NULL LastName
  • 为什么枚举会转换为函数?

    考虑 enum Colors Red Green Blue 它转换成这样 var Colors function Colors Colors Colors Red 0 Red Colors Colors Green 1 Green Colo
  • @classmethod 的位置

    装饰器类方法的源代码位于python源代码中的哪里 具体来说 我无法找到它在版本 2 7 2 中定义的确切文件 我没有回答你的问题 但下面的代码显示了装饰器可能相当于classmethod 用纯 Python 编写 因为源代码中的那个是用
  • Xcode — 在外部编辑器中快速打开当前文件

    是否可以设置键盘快捷键 或者在某处添加一些菜单项 以在外部编辑器中打开当前编辑的文件 显然我可以这样做 在文件树中右键单击 在Finder中显示 在窗口标题中右键单击 选择包含目录 右键单击文件 打开方式 应用程序 但步骤太多了 呵呵 我已
  • Hibernate 搜索查找短语的部分匹配

    在我的项目中 我们使用带有 lucene 分析器和 Solar 的 Hibernate Search 4 5 我向我的客户提供一个文本字段 当他们输入一个短语时 我想找到所有User名称包含给定短语的实体 例如 考虑数据库中具有以下标题的条
  • 什么时候问题对于正则表达式来说太复杂了?

    请不要回答显而易见的问题 但是有哪些限制标志告诉我们不应使用正则表达式来解决问题 例如 为什么完整的电子邮件验证对于正则表达式来说太复杂 正则表达式是以下内容的文本表示有限状态自动机 http en wikipedia org wiki F
  • 如何使用 C++ 模板减少编译时间

    我正在将我的 C 应用程序的一部分从使用旧的 C 类型数组更改为模板化的 C 容器类 看这个问题 https stackoverflow com questions 2472944 good c array class for dealin
  • iOS 11 iPhone X 模拟器选项卡栏图标和标题呈现在顶部,相互覆盖

    有人对 iPhone X 模拟器的 UITabBar 组件有疑问吗 我的似乎将图标和标题渲染在彼此之上 我不确定我是否遗漏了任何东西 我也在 iPhone 8 模拟器中运行了它 以及一个实际设备 它看起来很好 正如故事板 iPhone X
  • Cloudformation - 无法导入资源

    我正在创建 Step Functions 并希望在 cloudformation 代码中引用 Lambda 函数 lambda 已经从单独的堆栈创建并导出为LambdaA从那个堆栈 当我尝试导入时遇到问题LambdaA进入我的步骤功能代码
  • 支持不同语言

    我有 textView 和 ListView 我在列表视图中列出了支持语言 当我单击任何语言 Textview 文本需要更改时 Code String lang new String English French ListView list
  • Node.js 服务器有多个并发请求,它是如何工作的?

    我知道node js是单线程 异步 非阻塞I O 我读过很多相关内容 例如 PHP 每个请求使用一个线程 但 Node 只对所有请求使用一个线程 就像这样 假设有三个请求a b c同时到达node js服务器 其中三个请求需要大型阻塞操作