news 2026/4/18 11:00:35

【Node】单线程的Node.js为什么可以实现多线程?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Node】单线程的Node.js为什么可以实现多线程?

前言

很多刚接触 Node.js 的开发者都会有一个疑问:既然 Node.js 是单线程的,为什么又能使用 Worker Threads 这样的多线程模块呢?

今天我们就来解开这个看似矛盾的技术谜题。

👀 脑海里先有个印象:【Node.js 主线程】是单线程的,但【可以通过其他方式】实现并行处理

什么是 Node.js 的"单线程"?

事件循环(Event Loop)机制

javascript

体验AI代码助手

代码解读

复制代码

// 这是一个简单的 Node.js 程序 console.log('开始执行') setTimeout(() => { console.log('定时器回调') }, 1000) console.log('继续执行') // 输出顺序: // 开始执行 // 继续执行 // 定时器回调

核心特点

  • Node.js 有一个主线程负责执行 JavaScript 代码
  • 这个主线程运行着事件循环,按顺序处理任务
  • I/O 操作(文件读写、网络请求等)被【委托给系统底层】,不阻塞主线程

单线程的优势

javascript

体验AI代码助手

代码解读

复制代码

// 单线程模型简单易懂 let count = 0 function increment() { count++ console.log(count) } increment() // 输出 1 increment() // 输出 2 // 不用担心多线程的竞争条件问题

优点

  • ✅ 编程模型简单
  • ✅ 避免复杂的线程同步问题
  • ✅ 上下文切换开销小

那为什么还需要多线程?

单线程的局限性

javascript

体验AI代码助手

代码解读

复制代码

// CPU 密集型任务会阻塞事件循环 function heavyCalculation() { let result = 0 for (let i = 0; i < 1000000000; i++) { result += Math.sqrt(i) * Math.sin(i) } return result } console.log('任务开始') heavyCalculation() // 在这期间,其他任务都无法执行! console.log('任务结束,但用户界面会卡住')

问题暴露

  • 一个复杂的计算任务会阻塞整个应用程序
  • 无法充分利用多核 CPU 的性能
  • 对于计算密集型应用性能受限

解开谜题:Node.js 的多线程能力

底层真相:Node.js 不是完全单线程!!!

实际上,Node.js 的架构是下面这样的:

css

体验AI代码助手

代码解读

复制代码

┌─────────────────────────────┐ │ Node.js 进程 │ ├─────────────────────────────┤ │ ┌─────────────────────┐ │ │ │ JavaScript主线程 │ ← 我们写的代码在这里运行! │ └─────────────────────┘ │ │ │ │ ┌─────────────────────┐ │ │ │ libuv线程池 │ ← 处理文件I/O、DNS等 │ └─────────────────────┘ │ │ │ │ ┌─────────────────────┐ │ │ │ V8后台线程 │ ← 垃圾回收等 │ └─────────────────────┘ │ └─────────────────────────────┘

重点需要理解的内容

  • JavaScript 执行环境是单线程的。
  • Node.js 运行时本身使用了多线程
  • libuv 库提供了线程池来处理某些类型的 I/O 操作

补充知识:

Node.js 的 JavaScript 执行环境确实是单线程的,这意味着你的 JavaScript 代码是在一个主线程中顺序执行的,这个主线程运行着事件循环机制。

然而,Node.js 运行时本身是基于 C++ 的,它内部使用了多线程技术:libuv 这个底层库提供了一个线程池,当 JavaScript 代码执行到某些特定的异步 I/O 操作(如文件系统操作、DNS 查找等)时,这些任务会被提交到 libuv 的线程池中由后台线程执行,从而避免阻塞 JavaScript 主线程;

此外,V8 引擎也会使用一些后台线程来处理垃圾回收等任务。

所以,JavaScript 代码的执行是单线程的,但 Node.js 平台的底层实现是多线程的。

Worker Threads 的工作原理

javascript

体验AI代码助手

代码解读

复制代码

const {Worker, isMainThread} = require('worker_threads') if (isMainThread) { // 这是在主线程 console.log('主线程 ID:', process.pid) // 创建新的工作线程 const worker = new Worker( ` const { parentPort } = require('worker_threads'); console.log('工作线程中执行'); parentPort.postMessage('来自工作线程的消息'); `, {eval: true} ) worker.on('message', msg => { console.log('主线程收到:', msg) }) } else { // 这是在工作线程中(这段代码不会在这里执行) }

工作机制

  1. 每个 Worker Thread 都有自己独立的 JavaScript 执行环境
  2. 工作线程与主线程内存不共享(但可以通过 SharedArrayBuffer 共享)
  3. 线程间通过消息传递进行通信

为什么这样设计?

历史演进

  1. 最初设计:专注于 I/O 密集型任务,单线程+事件循环足够高效
  2. 需求变化:JavaScript 应用场景扩展到计算密集型领域
  3. 技术演进:引入 Worker Threads 来弥补单线程的不足

设计哲学

javascript

体验AI代码助手

代码解读

复制代码

// 正确的使用方式:主线程负责协调,工作线程负责计算 class TaskManager { async processBigData(data) { // 主线程:任务分发和结果收集 const promises = data.chunks.map(chunk => this.runInWorker('./calculation-worker.js', chunk)) // 不阻塞主线程,可以同时处理其他请求 const results = await Promise.all(promises) return this.aggregateResults(results) } }

这样设计的好处

  • 保持主线程的轻量和响应性
  • 将重型计算卸载到工作线程
  • 既享受单线程的简单性,又获得多线程的计算能力

下面举一些现实开发中的应用 🌰

🌰 例子 1:Web 服务器中的计算任务

javascript

体验AI代码助手

代码解读

复制代码

const express = require('express') const {Worker} = require('worker_threads') const app = express() app.get('/fast-request', (req, res) => { // 快速响应,不阻塞 res.json({status: 'ok', message: '立即返回'}) }) app.get('/heavy-calculation', async (req, res) => { // 重型计算交给工作线程 const result = await runInWorker('./heavy-math.js', req.query.data) res.json({result}) }) // 主线程始终保持响应

🌰 例子 2:数据处理管道

javascript

体验AI代码助手

代码解读

复制代码

async function processLargeDataset(dataset) { const chunkSize = Math.ceil(dataset.length / 4) // 分成4份 const workers = [] for (let i = 0; i < 4; i++) { const chunk = dataset.slice(i * chunkSize, (i + 1) * chunkSize) workers.push(createWorker('./data-processor.js', chunk)) } // 并行处理,大大加快速度 const results = await Promise.all(workers) return results.flat() }

✍️ 总结

核心要点回顾

  1. Node.js 的单线程指的是 JavaScript 执行环境是单线程的
  2. 底层实现使用了多线程技术来处理 I/O 等操作
  3. Worker Threads让我们能够在应用层面使用多线程能力
  4. 设计目标是保持【主线程的响应性】,同时获得并行计算的好处

👍 最佳实践

  • 常规 I/O 操作:使用原生 Node.js 单线程 + 异步模式
  • CPU 密集型任务:使用 Worker Threads 避免阻塞主线程
  • 高并发 Web 服务:使用 Cluster 模块充分利用多核 CPU

😎 回答标题的问题

Node.js 既是单线程的,又支持多线程,这并不矛盾:

  • 单线程:指 JavaScript 代码的执行方式,简化编程模型
  • 多线程能力:通过底层库和 Worker Threads 模块提供,解决性能瓶颈

作者:你的人类朋友
链接:https://juejin.cn/post/7557347203514515494
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 1:32:21

电商促销语音自动生成:Sambert-Hifigan落地实战

电商促销语音自动生成&#xff1a;Sambert-Hifigan落地实战 &#x1f4cc; 背景与需求&#xff1a;为什么需要多情感语音合成&#xff1f; 在电商平台的营销场景中&#xff0c;个性化、高吸引力的语音内容正成为提升用户转化率的重要手段。无论是商品详情页的自动播报、直播带货…

作者头像 李华
网站建设 2026/4/17 22:01:22

十分钟体验LLaMA-Factory微调:云端GPU镜像的便捷体验

十分钟体验LLaMA-Factory微调&#xff1a;云端GPU镜像的便捷体验 作为一名产品经理&#xff0c;你可能经常需要快速验证LLaMA模型的效果&#xff0c;但技术团队资源紧张&#xff0c;自己又不想陷入复杂的部署流程。本文将介绍如何通过预置的LLaMA-Factory镜像&#xff0c;在十分…

作者头像 李华
网站建设 2026/4/17 17:35:40

企业级系统SSL证书路径问题实战解决方案

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个企业SSL证书管理模拟器&#xff0c;模拟以下场景&#xff1a;1) 多层级CA证书链 2) 混合环境(Java/.NET) 3) 证书自动更新机制。要求&#xff1a;使用DeepSeek模型生成诊断…

作者头像 李华
网站建设 2026/4/18 3:22:13

AI配音成本大缩水:Sambert-Hifigan镜像部署,替代商业TTS方案

AI配音成本大缩水&#xff1a;Sambert-Hifigan镜像部署&#xff0c;替代商业TTS方案 一、中文多情感语音合成的技术演进与成本挑战 在智能客服、有声书生成、短视频配音等应用场景中&#xff0c;高质量的中文多情感语音合成&#xff08;Text-to-Speech, TTS&#xff09; 正变…

作者头像 李华
网站建设 2026/4/18 3:20:28

DEVSIDECAR vs 传统开发:效率提升300%的秘诀

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 设计一个效率对比工具&#xff0c;展示DEVSIDECAR与传统开发的差异。功能包括&#xff1a;1. 计时器记录开发时间&#xff1b;2. 错误率统计&#xff1b;3. 代码质量分析&#xff…

作者头像 李华
网站建设 2026/4/18 3:18:19

如何用Sambert-HifiGan构建语音合成PaaS平台

如何用Sambert-HifiGan构建语音合成PaaS平台 &#x1f3af; 业务场景与痛点分析 随着智能客服、有声阅读、虚拟主播等AI应用的普及&#xff0c;高质量的中文多情感语音合成&#xff08;Text-to-Speech, TTS&#xff09;已成为企业级服务的关键能力。传统TTS系统往往存在音质粗糙…

作者头像 李华