Node.js 内部结构

假设你去一家餐厅,有一位厨师承诺“我可以同时为数百人做饭,而你们不会挨饿”,听起来不可能,对吧?您可以将这个单一检查视为 node js,它管理所有这些多个订单,并且仍然为所有顾客提供食物。

每当你问某人“什么是 node js?”时,人们总是得到答案“node js 是一个运行时,用于在浏览器环境之外运行 javasc++ript”。

但是,运行时是什么意思?…运行时环境是一种软件基础设施,其中代码执行被编写成特定的编程语言。它拥有运行代码、处理错误、管理内存以及与底层操作系统或硬件交互的所有工具、库和功能。

node js 拥有所有这些。

google v8 引擎来运行代码。

fs、crypto、http 等核心库和 api

libuv 和事件循环等基础设施支持异步和非阻塞 i/o 操作。

所以,我们现在可以知道为什么 node js 被称为运行时了。

此运行时由两个独立的依赖项组成,v8libuv.

v8 是 google chrome 中也使用的引擎,由 google 开发和管理。在 node js 中,它执行 javascript 代码。当我们运行命令 node index.js 时,node js 会将此代码传递给 v8 引擎。 v8 处理该代码、执行它并提供结果。例如,如果您的代码记录“hello, world!”对于控制台,v8 处理实现此操作的实际执行。

libuv 库包含 c++ 代码,当我们需要网络、i/o 操作或与时间相关的操作等功能时,可以使用该代码访问操作系统。它充当 node js 和操作系统之间的桥梁。

libuv 处理以下操作:

文件系统操作:读取或写入文件(fs.readfile、fs.writefile)。

网络:处理 http 请求、套接字或连接到服务器。

计时器:管理 settimeout 或 setinterval 等函数。

文件读取等任务由 libuv 线程池处理,计时器由 libuv 的计时器系统处理,网络调用由操作系统级 api 处理。

node js 是单线程的吗?

看下面的例子。

const fs = require('fs');const path = require('path');const filepath = path.join(__dirname, 'file.txt');const readfilewithtiming = (index) => {  const start = date.now();  fs.readfile(filepath, 'utf8', (err, data) => {    if (err) {      console.error(`error reading the file for task ${index}:`, err);      return;    }    const end = date.now();    console.log(`task ${index} completed in ${end - start}ms`);  });};const startoverall = date.now();for (let i = 1; i  {  const endoverall = date.now();  console.log(`total execution time: ${endoverall - startoverall}ms`);});

我们正在读取同一个文件四次,并且我们正在记录读取这些文件的时间。

我们得到此代码的以下输出。

task 1 completed in 50mstask 2 completed in 51mstask 3 completed in 52mstask 4 completed in 53mstotal execution time: 54ms

我们可以看到我们几乎在第 50 毫秒完成了所有四个文件的读取。如果 node js 是单线程的话,那么这些文件读取操作是如何同时完成的呢?

这个问题回答了libuv库使用线程池。线程池是一堆线程。默认情况下,线程池大小为 4,意味着 libuv 可以一次处理 4 个请求。

考虑另一种情况,我们不是读取一个文件 4 次,而是读取该文件 6 次。

const fs = require('fs');const path = require('path');const filepath = path.join(__dirname, 'file.txt');const readfilewithtiming = (index) => {  const start = date.now();  fs.readfile(filepath, 'utf8', (err, data) => {    if (err) {      console.error(`error reading the file for task ${index}:`, err);      return;    }    const end = date.now();    console.log(`task ${index} completed in ${end - start}ms`);  });};const startoverall = date.now();for (let i = 1; i  {  const endoverall = date.now();  console.log(`total execution time: ${endoverall - startoverall}ms`);});

输出将如下所示:

task 1 completed in 50mstask 2 completed in 51mstask 3 completed in 52mstask 4 completed in 53mstask 5 completed in 101mstask 6 completed in 102mstotal execution time: 103ms

image description

假设读操作1和2完成并且线程1和2空闲。

Node.js 内部结构

您可以看到,前 4 次我们读取文件的时间几乎相同,但是当我们第 5 次和第 6 次读取该文件时,完成读取操作所需的时间几乎是前 4 次读取操作的两倍。

发生这种情况是因为线程池大小默认为 4,因此同时处理四个读取操作,但我们再次读取文件 2 次(第 5 次和第 6 次),然后 libuv 等待,因为所有线程都有一些工作。当四个线程之一完成执行时,将对该线程处理第 5 次读操作,并且将执行第 6 次读操作。这就是为什么需要更多时间的原因。

所以,node js 不是单线程的。

但是,为什么有些人将其称为单线程?

这是因为主事件循环是单线程的。该线程负责执行 node js 代码,包括处理异步回调和协调任务。它不直接处理文件 i/o 等阻塞操作。

代码执行流程是这样的。

同步代码(v8):

node.js 使用 v8 javascript 引擎逐行执行所有同步(阻塞)代码。

委派的异步任务:

诸如 fs.readfile、settimeout 或 http 请求之类的异步操作被发送到 libuv 库或其他子系统(例如操作系统)。

任务执行:

文件读取等任务由 libuv 线程池处理,计时器由 libuv 的计时器系统处理,网络调用由操作系统级 api 处理。

回调排队:

异步任务完成后,其关联的回调将被发送到事件循环的队列。

事件循环执行回调:

事件循环从队列中获取回调并一一执行它们,确保非阻塞执行。

您可以使用 process.env.uv_threadpool_size = 8.

更改线程池大小

现在,我在想,如果我们设置大量的线程,那么我们也将能够处理大量的请求。我希望你能像我一样思考这个问题。

但是,这与我们的想法相反。

如果我们增加线程数量超过一定限制,那么它会减慢你的代码执行速度。

看下面的例子。

const fs = require('fs');const path = require('path');// set uv_threadpool_size to 100 (a high value) for this exampleprocess.env.uv_threadpool_size = 100;const filepath = path.join(__dirname, 'largefile.txt');// function to simulate reading multiple files asynchronouslyconst readfilewithtiming = (index) => {  const start = date.now();  fs.readfile(filepath, 'utf8', (err, data) => {    if (err) {      console.error(`error reading the file for task ${index}:`, err);      return;    }    const end = date.now();    console.log(`task ${index} completed in ${end - start}ms`);  });};const startoverall = date.now();for (let i = 1; i  {  const endoverall = date.now();  console.log(`total execution time: ${endoverall - startoverall}ms`);});

输出:

具有高线程池大小(100 个线程)

task 1 completed in 100mstask 2 completed in 98mstask 3 completed in 105mstask 4 completed in 95mstask 5 completed in 120mstask 6 completed in 130mstask 7 completed in 135mstask 8 completed in 140mstask 9 completed in 125mstask 10 completed in 150mstotal execution time: 700ms

现在,以下输出是当我们将线程池大小设置为 4(默认大小)时的输出。

使用默认线程池大小(4 个线程)

Task 1 completed in 100msTask 2 completed in 98msTask 3 completed in 105msTask 4 completed in 95msTask 5 completed in 100msTask 6 completed in 98msTask 7 completed in 102msTask 8 completed in 104msTask 9 completed in 106msTask 10 completed in 99msTotal execution time: 600ms

可以看到总的执行时间有100ms的差异。总执行时间(线程池大小 4)为 600 毫秒,总执行时间(线程池大小 100)为 700 毫秒。因此,线程池大小为 4 花费的时间更少。

为什么线程数多!=可以同时处理更多任务?

第一个原因是每个线程都有自己的堆栈和资源需求。如果增加线程数量,最终会导致内存或 cpu 资源不足的情况。

第二个原因是操作系统必须调度线程。如果线程太多,操作系统将花费大量时间在线程之间切换(上下文切换),这会增加开销并降低性能,而不是提高性能。

现在,我们可以说,这不是增加线程池大小以实现可扩展性和高性能,而是使用正确的架构,例如集群,并了解任务性质(i/o 与 cpu 限制) )以及 node.js 的事件驱动模型如何工作。

感谢您的阅读。

以上就是Node.js 内部结构的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1498155.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月19日 20:12:55
下一篇 2025年12月19日 20:13:11

相关推荐

  • CSS mask属性无法获取图片:为什么我的图片不见了?

    CSS mask属性无法获取图片 在使用CSS mask属性时,可能会遇到无法获取指定照片的情况。这个问题通常表现为: 网络面板中没有请求图片:尽管CSS代码中指定了图片地址,但网络面板中却找不到图片的请求记录。 问题原因: 此问题的可能原因是浏览器的兼容性问题。某些较旧版本的浏览器可能不支持CSS…

    2025年12月24日
    900
  • 为什么设置 `overflow: hidden` 会导致 `inline-block` 元素错位?

    overflow 导致 inline-block 元素错位解析 当多个 inline-block 元素并列排列时,可能会出现错位显示的问题。这通常是由于其中一个元素设置了 overflow 属性引起的。 问题现象 在不设置 overflow 属性时,元素按预期显示在同一水平线上: 不设置 overf…

    2025年12月24日 好文分享
    400
  • 网页使用本地字体:为什么 CSS 代码中明明指定了“荆南麦圆体”,页面却仍然显示“微软雅黑”?

    网页中使用本地字体 本文将解答如何将本地安装字体应用到网页中,避免使用 src 属性直接引入字体文件。 问题: 想要在网页上使用已安装的“荆南麦圆体”字体,但 css 代码中将其置于第一位的“font-family”属性,页面仍显示“微软雅黑”字体。 立即学习“前端免费学习笔记(深入)”; 答案: …

    2025年12月24日
    000
  • 为什么我的特定 DIV 在 Edge 浏览器中无法显示?

    特定 DIV 无法显示:用户代理样式表的困扰 当你在 Edge 浏览器中打开项目中的某个 div 时,却发现它无法正常显示,仔细检查样式后,发现是由用户代理样式表中的 display none 引起的。但你疑问的是,为什么会出现这样的样式表,而且只针对特定的 div? 背后的原因 用户代理样式表是由…

    2025年12月24日
    200
  • inline-block元素错位了,是为什么?

    inline-block元素错位背后的原因 inline-block元素是一种特殊类型的块级元素,它可以与其他元素行内排列。但是,在某些情况下,inline-block元素可能会出现错位显示的问题。 错位的原因 当inline-block元素设置了overflow:hidden属性时,它会影响元素的…

    2025年12月24日
    000
  • 为什么 CSS mask 属性未请求指定图片?

    解决 css mask 属性未请求图片的问题 在使用 css mask 属性时,指定了图片地址,但网络面板显示未请求获取该图片,这可能是由于浏览器兼容性问题造成的。 问题 如下代码所示: 立即学习“前端免费学习笔记(深入)”; icon [data-icon=”cloud”] { –icon-cl…

    2025年12月24日
    200
  • 为什么使用 inline-block 元素时会错位?

    inline-block 元素错位成因剖析 在使用 inline-block 元素时,可能会遇到它们错位显示的问题。如代码 demo 所示,当设置了 overflow 属性时,a 标签就会错位下沉,而未设置时却不会。 问题根源: overflow:hidden 属性影响了 inline-block …

    2025年12月24日
    000
  • 为什么我的 CSS 元素放大效果无法正常生效?

    css 设置元素放大效果的疑问解答 原提问者在尝试给元素添加 10em 字体大小和过渡效果后,未能在进入页面时看到放大效果。探究发现,原提问者将 CSS 代码直接写在页面中,导致放大效果无法触发。 解决办法如下: 将 CSS 样式写在一个单独的文件中,并使用 标签引入该样式文件。这个操作与原提问者观…

    2025年12月24日
    000
  • 为什么我的 em 和 transition 设置后元素没有放大?

    元素设置 em 和 transition 后不放大 一个 youtube 视频中展示了设置 em 和 transition 的元素在页面加载后会放大,但同样的代码在提问者电脑上没有达到预期效果。 可能原因: 问题在于 css 代码的位置。在视频中,css 被放置在单独的文件中并通过 link 标签引…

    2025年12月24日
    100
  • 为什么在父元素为inline或inline-block时,子元素设置width: 100%会出现不同的显示效果?

    width:100%在父元素为inline或inline-block下的显示问题 问题提出 当父元素为inline或inline-block时,内部元素设置width:100%会出现不同的显示效果。以代码为例: 测试内容 这是inline-block span 效果1:父元素为inline-bloc…

    2025年12月24日
    400
  • 构建模拟:从头开始的实时交易模拟器

    简介 嘿,开发社区!我很高兴分享我的业余项目 Simul8or – 一个实时日间交易模拟器,旨在为用户提供一个无风险的环境来练习交易策略。该项目 100% 构建在 ASP.NET WebForms、C#、JavaScript、CSS 和 SQL Server 技术堆栈上,没有外部库或框架。从头开始构…

    2025年12月24日
    300
  • Bear 博客上的浅色/深色模式分步指南

    我最近使用偏好颜色方案媒体功能与 light-dark() 颜色函数相结合,在我的 bear 博客上实现了亮/暗模式切换。 我是这样做的。 第 1 步:设置 css css 在过去几年中获得了一些很酷的新功能,包括 light-dark() 颜色函数。此功能可让您为任何元素指定两种颜色 &#8211…

    2025年12月24日
    100
  • 如何在 Web 开发中检测浏览器中的操作系统暗模式?

    检测浏览器中的操作系统暗模式 在 web 开发中,用户界面适应操作系统(os)的暗模式设置变得越来越重要。本文将重点介绍检测浏览器中 os 暗模式的方法,从而使网站能够针对不同模式调整其设计。 w3c media queries level 5 最新的 web 标准引入了 prefers-color…

    2025年12月24日
    000
  • 如何使用 CSS 检测操作系统是否处于暗模式?

    如何在浏览器中检测操作系统是否处于暗模式? 新发布的 os x 暗模式提供了在 mac 电脑上使用更具沉浸感的用户界面,但我们很多人都想知道如何在浏览器中检测这种设置。 新标准 检测操作系统暗模式的解决方案出现在 w3c media queries level 5 中的最新标准中: 立即学习“前端免…

    2025年12月24日
    000
  • 如何检测浏览器环境中的操作系统暗模式?

    浏览器环境中的操作系统暗模式检测 在如今科技的海洋中,越来越多的设备和软件支持暗模式,以减少对眼睛的刺激并营造更舒适的视觉体验。然而,在浏览器环境中检测操作系统是否处于暗模式却是一个令人好奇的问题。 检测暗模式的标准 要检测操作系统在浏览器中是否处于暗模式,web 开发人员可以使用 w3c 的媒体查…

    2025年12月24日
    200
  • 浏览器中如何检测操作系统的暗模式设置?

    浏览器中的操作系统暗模式检测 近年来,随着用户对夜间浏览体验的偏好不断提高,操作系统已开始引入暗模式功能。作为一名 web 开发人员,您可能想知道如何检测浏览器中操作系统的暗模式状态,以相应地调整您网站的设计。 新 media queries 水平 w3c 的 media queries level…

    2025年12月24日
    000
  • 我在学习编程的第一周学到的工具

    作为一个刚刚完成中学教育的女孩和一个精通技术并热衷于解决问题的人,几周前我开始了我的编程之旅。我的名字是OKESANJO FATHIA OPEYEMI。我很高兴能分享我在编码世界中的经验和发现。拥有计算机科学背景的我一直对编程提供的无限可能性着迷。在这篇文章中,我将反思我在学习编程的第一周中获得的关…

    2025年12月24日
    000
  • 花 $o 学习这些编程语言或免费

    → Python → JavaScript → Java → C# → 红宝石 → 斯威夫特 → 科特林 → C++ → PHP → 出发 → R → 打字稿 []https://x.com/e_opore/status/1811567830594388315?t=_j4nncuiy2wfbm7ic…

    2025年12月24日
    000
  • css和c的区别是什么

    区别是:1、C语言是一门面向过程、抽象化的通用程序设计语言、计算机编程语言,广泛应用于底层开发;2、CSS是一种用来表现HTML或XML等文件样式的计算机语言,可以做到网页和内容进行分离的一种样式语言。 本教程操作环境:windows7系统、CSS3&&HTML5版、Dell G3电…

    2025年12月24日
    000
  • HTML5怎么制作广告_HTML5用动画与交互制横幅或弹窗广告吸引点击【制作】

    可利用HTML5结合CSS3动画、Canvas、Web Animations API、Intersection Observer和video标签制作互动广告:一用@keyframes实现横幅入场动画;二用Canvas绘制并响应悬停;三用Web Animations API控制弹窗时序;四用Inter…

    2025年12月23日
    000

发表回复

登录后才能评论
关注微信