0

0

如何理解 Node.js 不是完全的单线程的程序(浅析)

青灯夜游

青灯夜游

发布时间:2022-02-08 18:20:25

|

2110人浏览过

|

来源于掘金社区

转载

为什么说 node.js 不是完全的单线程?如何理解?下面本篇文章就来带大家探讨一下,希望对大家有所帮助!

如何理解 Node.js 不是完全的单线程的程序(浅析)

相信大家都知道 node 是一个单线程程序,使用了 Event Loop 可以做到多并发。可惜这是不完全正确的。

那么为什么说 Node.js 不是完全的单线程的程序呢?

Node.js 是单线程的程序*

所有我们自己写的 Javsacript,V8, event loop都跑在同一个线程里面,也就是 main thrad。

哎嗨,这不正说明 node 是单线程的吗?

但是也许你不知道 node 有很多模块背后都是 C++ code。

虽然 node 没有给使用者暴露控制 thread 的权限,但是 C++ 是可以使用多线程的。

那么什么时候 node 会使用多线程呢?

  • 如果一个 node 方法,背后调用C++的同步方法,那么都是跑在 main thread 里面的。

  • 如果一个 node 方法,背后调用C++的异步方法,有时候不是跑在 main thread 里面的。

Talk is cheap, show me the code.

同步方法,跑在 main thread 里面

这里 crypto 相关模块,很多是 C++ 写的。下面一段程序是计算hash的函数,一般用来存储密码。

import { pbkdf2Sync } from "crypto";
const startTime = Date.now();
let index = 0;
for (index = 0; index < 3; index++) {
    pbkdf2Sync("secret", "salt", 100000, 64, "sha512");
    const endTime = Date.now();
    console.log(`${index} time, ${endTime - startTime}`);
}
const endTime = Date.now();
console.log(`in the end`);

输出的时间,

0 time, 44 
1 time, 90
2 time, 134
in the end

可以看到每次大概都是花费~45ms,代码 main thread 上顺序执行。

注意最后的输出是谁? 注意这里一次 hash 在我的 cpu 需要~45ms。

异步 pbkdf2 方法,不跑在 main thread 里面

import { cpus } from "os";
import { pbkdf2 } from "crypto";
console.log(cpus().length);
let startTime = console.time("time-main-end");
for (let index = 0; index < 4; index++) {
    startTime = console.time(`time-${index}`);
    pbkdf2("secret", `salt${index}`, 100000, 64, "sha512", (err, derivedKey) => {
        if (err) throw err;
        console.timeEnd(`time-${index}`);
    });
}
console.timeEnd("time-main-end");

输出的时间,

time-main-end: 0.31ms
time-2: 45.646ms
time-0: 46.055ms
time-3: 46.846ms
time-1: 47.159ms

这里看到,main thread 早早结束,然而每次计算的时间都是45ms,要知道一个 cpu 计算 hash 的时间是45ms,这里 node 绝对使用了多个线程进行hash计算。

如果我这里把调用次数改成10次,那么时间如下,可以看到随着CPU核数的用完,时间也在增加。再一次证明node 绝对使用了多个线程进行hash计算。

time-main-end: 0.451ms
time-1: 44.977ms
time-2: 46.069ms
time-3: 50.033ms
time-0: 51.381ms
time-5: 96.429ms // 注意这里,从第五次时间开始增加了
time-7: 101.61ms
time-4: 113.535ms
time-6: 121.429ms
time-9: 151.035ms
time-8: 152.585ms

虽然这里证明了,node绝对启用了多线程。但是有一点点小小的问题?我的电脑的CPU是AMD R5-5600U,有6个核心12线程啊。但是为什么时间是从第五次开始增加的呢,node没有完全利用我的CPU啊?

原因是什么呢?

Node 使用了预定义的线程池,这个线程池的大小默认是4.

export UV_THREADPOOL_SIZE=6

Mokker AI
Mokker AI

AI产品图添加背景

下载

让我们在看一个例子,

HTTP request

import { request } from "https";
const options = {
  hostname: "www.baidu.com",
  port: 443,
  path: "/img/PC_7ac6a6d319ba4ae29b38e5e4280e9122.png",
  method: "GET",
};

let startTime = console.time(`main`);

for (let index = 0; index < 15; index++) {
  startTime = console.time(`time-${index}`);
  const req = request(options, (res) => {
    console.log(`statusCode: ${res.statusCode}`);
    console.timeEnd(`time-${index}`);
    res.on("data", (d) => {
      // process.stdout.write(d);
    });
  });

  req.on("error", (error) => {
    console.error(error);
  });

  req.end();
}

console.timeEnd("main");
main: 13.927ms
time-2: 83.247ms
time-4: 89.641ms
time-3: 91.497ms
time-12: 91.661ms
time-5: 94.677ms
.....
time-8: 134.026ms
time-1: 143.906ms
time-13: 140.914ms
time-10: 144.088ms

这里主程序也早早结束了,这里我启动 http request 去下载15次图片,他们花费的时间并没有成倍增加,似乎不受限于线程池/cpu的影响。

为什么啊??Node 到底有没有在使用线程池啊?

如果 Node 背后的 C++ 的异步方法,首先会尝试是否有内核异步支持,比如这里网络请是使用 epoll (Linux),如果内核没有提供异步方式,Node才会使用自己的线程池。。

所以 http 请求虽然是异步,不过是由内核实现的,等到内核完成后,会通知C++, C++会通知给 main thread 处理callback。

那么 Node 哪些异步方法会使用线程池呢?哪些不会呢?

  • 原生 Kernal Async

    • TCP/UDP server client
    • Unix Domain Sockets (IPC)
    • pipes
    • dns.resolveXXX
    • tty input(stdin etc)
    • Unix signals
    • Child process
  • Thread pool

    • fs.*
    • dns.lookup
    • pipe (edge case)

这也是大部分 Node 优化的切入点。

但是这些怎么和最重要的 Event Loop 结合起来呢?

Event Loop

相信大家都对 Event loop 非常熟悉了。Event loop 好比一个分发员,

  • 如果是遇到普通 javascript 程序或者是 callback,交给 V8 处理。

  • 如果遇到同步方法后背是 C++ 写的,交给C++,跑在 main thread。

  • 如果遇到异步方法后背是 C++ 写的,如果有内核异步支持,从main thread 交给内核处理。

  • 如果是异步方法后背是 C++ 写的,如果没有内核异步支持,从 main thread 交给 thread pool。

  • thread pool 和内核有结果都会把结果返回 event loop,如果注册的有 javascript callback,就交给V8进行处理。

然后如此循环,直到没有东西可以处理。

所以 Node 不完全是单线程程序。

更多node相关知识,请访问:nodejs 教程

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
node.js调试
node.js调试

node.js调试可以使用console.log()输出调试信息、断点调试和第三方调试工具。详细介绍:1、console.log()输出调试信息,通过在代码中插入console.log()语句,开发人员可以在控制台输出变量的值、函数的执行结果等信息,以便观察代码的执行流程和状态;2、断点调试,可以在代码中设置断点,以便在特定位置暂停代码的执行,观察变量的值和执行流程等。

362

2023.09.19

JavaScript 全栈开发基础(Node.js + 前端)
JavaScript 全栈开发基础(Node.js + 前端)

本专题系统介绍 JavaScript 在全栈开发中的核心知识结构,涵盖 Node.js 基础、Express/Koa 接口构建、前端交互设计、模块化与包管理、数据库连接、前后端数据通信与部署流程。通过完整项目示例,帮助学习者掌握从浏览器到服务器的一体化开发能力,实现真正意义上的全栈入门。

118

2025.11.26

Node.js后端开发与Express框架实践
Node.js后端开发与Express框架实践

本专题针对初中级 Node.js 开发者,系统讲解如何使用 Express 框架搭建高性能后端服务。内容包括路由设计、中间件开发、数据库集成、API 安全与异常处理,以及 RESTful API 的设计与优化。通过实际项目演示,帮助开发者快速掌握 Node.js 后端开发流程。

422

2026.02.10

edge是什么浏览器
edge是什么浏览器

Edge是一款由Microsoft开发的网页浏览器,是Windows 10操作系统中默认的浏览器,其目标是提供更快、更安全、更现代化的浏览器体验。本专题为大家提供edge浏览器相关的文章、下载、课程内容,供大家免费下载体验。

1733

2023.08.21

IE浏览器自动跳转EDGE如何恢复
IE浏览器自动跳转EDGE如何恢复

ie浏览器自动跳转edge的解决办法:1、更改默认浏览器设置;2、阻止edge浏览器的自动跳转;3、更改超链接的默认打开方式;4、禁用“快速网页查看器”;5、卸载edge浏览器;6、检查第三方插件或应用程序等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

397

2024.03.05

如何解决Edge打开但没有标题的问题
如何解决Edge打开但没有标题的问题

若 Microsoft Edge 浏览器打开后无标题(窗口空白或标题栏缺失),可尝试以下方法解决: 重启 Edge:关闭所有窗口,重新启动浏览器。 重置窗口布局:右击任务栏 Edge 图标 → 选择「最大化」或「还原」。 禁用扩展:进入 edge://extensions 临时关闭插件测试。 重置浏览器设置:前往 edge://settings/reset 恢复默认配置。 更新或重装 Edge:检查最新版本,或通过控制面板修复

1038

2025.04.24

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

765

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

377

2025.12.24

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

37

2026.03.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Node.js 教程
Node.js 教程

共57课时 | 13.3万人学习

【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 2.1万人学习

Node.js-前端工程化必学
Node.js-前端工程化必学

共19课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号