代码库网站,建设网站方案,建设部施工安全管理网站,成都新站软件快速排名目录
单线程 Node.js
工作线程【Worker Threads】
Node.js 进程
进程缺点
工作线程
注意
集群进程模块【Cluster Process Module】
内部发生了什么#xff1f;
为什么要使用集群
注意#xff1a;
应用场景#xff1a;
内置 HTTP/2 支持
这个 HTTP/2 是什么
为什么要使用集群
注意
应用场景
内置 HTTP/2 支持
这个 HTTP/2 是什么
Node.js 如何提供对 HTTP/2 的支持
开始使用 http2
流【Streams API】
什么是流
为什么要使用 Streams
开始使用 Streams
结论
REPL (Read-Eval-Print Loop)
介绍
命令行快捷键
结论
结论 单线程的 Node.js
首先我们要知道Node.js 以其单线程架构而闻名。最初Node.js 是为 I/O 密集型任务如 Web 服务器而设计的。对于这些任务创建多个线程会增加管理线程同步和上下文切换的开销和复杂性。相反Node.js 采用了事件驱动的方法。
这种行为给 Node.js 带来了一些优点但也有局限性。
优点还行。但是局限性呢 Node.js 单线程事件循环带来的主要限制如下
CPU 密集型任务可能会阻塞循环大量计算可能会“冻结”循环从而影响其他请求的响应能力。 没有真正的并行任务仍然一个接一个地执行而不是同时执行。
为了解决这些限制Node.js在各个 Node.js 版本中引入了工作线程和集群模块。
工作线程【Worker Threads】 Node.js 进程
当 Node.js 进程启动时它会运行
一个进程进程是一个全局对象可以在任何地方访问并且包含有关当前正在执行的操作的信息。一个线程单线程意味着在给定的进程中一次只执行一组指令。一个事件循环这是了解 Node 最重要的方面之一。尽管 JavaScript 是单线程的但它却允许 Node 异步并具有非阻塞 I/O方法是通过回调、承诺和 async/await 尽可能将操作卸载到系统内核。一个 JS 引擎实例这是一个执行 JavaScript 代码的计算机程序。一个 Node.js 实例执行 Node.js 代码的计算机程序。
换句话说Node 在单线程上运行事件循环中一次只发生一个进程。一个代码一次执行代码不是并行执行的。这非常有用因为它简化了使用 JavaScript 的方式而不必担心并发问题。
采用这种方法构建的原因是 JavaScript 最初是为客户端交互如网页交互或表单验证创建的——不需要多线程的复杂性。
进程缺点
但是它也存在缺点如果代码占用大量 CPU例如在内存中进行大型数据集的复杂计算它可能会阻止其他进程的执行。同样如果向包含占用大量 CPU 的代码的服务器发出请求该代码可能会阻塞事件循环并阻止处理其他请求。
如果主事件循环必须等待直到执行完下一个命令则该函数被视为“阻塞”。 “非阻塞”函数将允许主事件循环在开始时立即继续并且通常在主循环完成后通过调用“回调”来提醒主循环。 黄金法则不要阻塞事件循环尽量保持其运行并注意避免任何可能阻塞线程的事情如同步网络调用或无限循环。 工作线程
对于CPU性能最好的解决方案就是Worker Threads 工作线程具有
一个流程多线程每个线程一个事件循环每个线程一个 JS 引擎实例每个线程一个 Node.js 实例
工作线程可以
卸载 CPU 密集型任务释放主线程以执行其他工作。实现并行并发执行任务以获得更快的性能。高效共享数据避免在进程之间复制数据的开销。
工作线程的特殊之处
ArrayBuffers将内存从一个线程转移到另一个线程SharedArrayBuffer可以从任一线程访问。它允许在线程之间共享内存仅限于二进制数据。Atomics可用它允许更高效地同时执行一些进程并允许在 JavaScript 中实现条件变量MessagePort用于不同线程之间的通信。可用于在不同的Worker之间传输结构化数据、内存区域和其他MessagePort。MessageChannel表示用于不同线程之间通信的异步、双向通信通道。WorkerData用于传递启动数据。一个任意的 JavaScript 值其中包含传递给此线程的 Worker 构造函数的数据的克隆。数据的克隆方式与使用postMessage()
API
const { worker, parentPort } require(‘worker_threads’)worker该类代表一个独立的 JavaScript 执行线程是parentPort消息端口的一个实例new Worker(filename)或new Worker(code, { eval: true }) 是启动 worker 的两种主要方式传递文件名或要执行的代码。建议在生产中使用文件名。worker.on(‘message’)worker/postMessage(data) 用于监听消息并在不同的线程之间发送消息。parentPort.on(‘message’), parentPort.postMessage(data) 使用 发送的消息parentPort.postMessage()将在使用 的父线程中可用worker.on(message)并且使用 从父线程发送的消息worker.postMessage()将在使用 的本线程中可用parentPort.on(message)。
例子
const { Worker } require(worker_threads);const worker new Worker(
const { parentPort } require(worker_threads);
parentPort.once(message,message parentPort.postMessage({ pong: message }));
, { eval: true });
worker.on(message, message console.log(message));
worker.postMessage(ping);
$ node --experimental-worker test.js
{ pong: ‘ping’ } 注意
工作线程共享内存创建和管理工作线程会产生一些开销因此请考虑其针对特定用例的益处与成本。线程安全至关重要使用同步机制来确保数据完整性。工作线程增加了复杂性因此请明智地将它们用于真正受益于并行性的任务。
集群进程模块【Cluster Process Module】 该cluster模块可分散 Node.js 应用程序的工作负载充分利用计算机服务器的全部处理能力。例如如果我们有一个 8 核处理器那么我们的工作就不必只集中在一个核心上而是可以分散到所有八个核心上。
使用cluster第一个核心将成为“主核心”而所有其他核心将成为“工作核心”。当请求进入应用程序时主进程将执行循环式检查询问“哪个工作核心现在可以处理此请求”满足要求的第一个工作核心将获得请求。重复此过程。
例子
const cluster require(cluster);if (cluster.isMaster) {// Master processconst numWorkers require(os).cpus().length;for (let i 0; i numWorkers; i) {cluster.fork();}cluster.on(exit, (worker, code, signal) {console.log(worker ${worker.process.pid} died );});
} else {// Worker process// Your application logic hereapp.listen(3000);
}
内部发生了什么
集群模块创建多个独立的 Node.js 进程每个进程都有自己的事件循环和内存空间。 这些进程在不同的核心上独立运行利用多个核心来提高性能水平扩展。 它通过创建一个主进程和多个工作进程来运行。主进程管理工作进程之间传入连接的分配。如果工作进程发生故障主进程可以重新生成一个新进程从而确保在发生故障时的稳健性。
为什么要使用集群
提高性能处理更高的流量并改善响应时间特别是对于 I/O 密集型任务。最大限度地提高资源利用率充分利用服务器中所有可用的核心显著提高处理能力。增强的容错能力如果一个工作程序崩溃其他工作程序仍可保持应用程序运行确保可靠性和正常运行时间。
注意
工作进程共享内存和资源因此请仔细考虑数据同步。集群模块增加了应用程序架构的复杂性因此请根据特定需求评估其优势与复杂性。
应用场景
高流量网站当单线程事件循环达到其极限时使用集群进行水平扩展有助于有效地管理庞大的用户群。长时间运行的任务如果某些请求涉及长时间操作如图像处理或数据加密则将它们分布在工作进程中可以提高其他请求的响应能力。容错至关重要对于关键任务应用程序集群模块对单个进程故障的恢复能力提供了宝贵的保护。
内置 HTTP/2 支持
虽然工作线程和集群模块解决了不同的问题但 Node.js 的模块通过提供对高效HTTP/2 协议的http2内置支持直接解决性能问题。
这个 HTTP/2 是什么
HTTP/2 是 HTTP/1.1 的后继者它带来了多项性能增强
多路复用支持在单个连接上同时发送和接收多个请求和响应消除了困扰 HTTP/1.1 的队头阻塞问题。报头压缩通过压缩来缩小报头大小从而大幅减少数据传输开销。服务器推送允许服务器在客户端请求资源之前主动向客户端发送资源从而可能加快页面加载时间。
Node.js 如何提供对 HTTP/2 的支持
Node.js 提供了一个http2用于 HTTP/2 的强大模块。以下是它提供的一些功能
创建 HTTP/2 服务器使用熟悉的 Node.js 服务器模式以及用于管理流和服务器推送功能的附加选项。处理 HTTP/2 客户端访问客户端功能以连接并与 HTTP/2 服务器交互。广泛的 API探索各种方法和事件来管理连接、流、推送机制和错误处理。
开始使用 http2
Node.js 文档提供了使用 http2 模块的详细指南和示例。但是仅提供链接是不够的。让我们通过一些实际示例来演示其用法。
1.创建一个基本的HTTP / 2服务器
const http2 require(http2);const server http2.createServer();server.on(stream, (stream, headers) {stream.respond({status: 200,content-type: text/plain,});stream.end(Hello from your HTTP/2 server!);
});server.listen(3000, () {console.log(Server listening on port 3000);
});
此代码创建了一个简单的服务器向通过 HTTP/2 连接的任何客户端发送“Hello”消息。2.处理客户请求
const http2 require(http2);const server http2.createServer();server.on(stream, (stream, headers) {const path headers[:path];if (path /) {stream.respond({status: 200,content-type: text/plain,});stream.end(Hello from HTTP/2 server!);} else {stream.respond({status: 404,content-type: text/plain,});stream.end(Not found);}
});server.listen(3000, () {console.log(Server listening on port 3000);
});
此代码扩展了前面的示例以处理不同的请求路径/并发送适当的响应。
流【Streams API】 Stream 是允许开发人员连续从源读取和写入数据的对象。Stream 是用于处理 Node.js 中连续数据集合的抽象接口。可读、可写、双工和转换是 Node.js 中的四种主要流类型。每个流都是一个eventEmitter实例它会在一定时间间隔内发出不同的事件。
什么是流 想象一下数据像水流一样流动 — — 这就是本质上的概念 流的一个独特功能是它不是一次性读取内存中的所有数据而是读取并处理小块数据。这样就不必一次性保存和处理整个文件。
Streams 可用于构建实际应用程序例如视频流应用程序使用此服务不必一次性下载所有视频或音频源而是可以立即观看视频并收听音频。这就是浏览器以连续的块流形式接收视频和音频的方式。如果这些网站在流式传输之前先等待整个视频和音频下载完毕则播放视频可能需要很长时间。
流基于一个称为缓冲区的概念进行工作。缓冲区是一种临时内存用于保存数据直到流被使用为止。
流表示随时间推移传递的连续数据块序列。Node.js 提供各种流类型每种类型都适用于不同的用例
可读流发出数据块以供使用非常适合读取文件、网络连接或用户输入。可写流允许写入数据块非常适合写入文件、网络连接或数据库。双工流结合读写功能适用于套接字或管道等双向通信。转换流在数据流过时对其进行修改从而实现加密、压缩或数据操作。
为什么要使用 Streams
在涉及大型数据集或连续数据流的场景中流非常有用。它们具有以下几个优点
内存效率它们分块处理数据避免一次将整个数据集加载到内存中。非阻塞特性它们不会阻塞主线程从而使应用程序在处理数据时保持响应。灵活性不同的流类型可满足各种数据处理需求。
开始使用 Streams
const fs require(fs);const readableStream fs.createReadStream(large_file.txt);readableStream.on(data, (chunk) {console.log(Received data chunk:, chunk.toString());
});readableStream.on(end, () {console.log(Finished reading file);
});
此代码large_file.txt分块读取文件并将其记录到控制台。
结论
流是允许从源读取数据并将数据写入目标的对象。可读、可写、双工和变换是 Node.js 中的四种基本流类型。管道方法是使用流的最简单、最容易的方法。链接是一种将一个流的输出连接到另一个流并创建多个流的操作链的机制。可读流中最重要的事件是数据事件和结束事件。可写流中最重要的事件是耗尽事件和完成事件。可读流可以操作流动心情或者暂停心情。
REPL (Read-Eval-Print Loop) REPL 是Read Evaluate Print Loop的缩写它是一种编程语言环境本质上是一个控制台窗口它接受单个表达式作为用户输入执行该表达式并在执行后将结果返回到控制台。REPL 会话允许快速测试和执行基本的 JavaScript 程序。可以在 REPL 上轻松测试代码的独立部分。 想象一个沙盒环境可以在其中试验代码片段、测试想法并获得即时反馈 - 这就是 REPL 的本质。 介绍
REPLREAD、EVAL、PRINT、LOOP是相当于Unix/Linux中Shell的命令行环境。Node在安装时自带REPL环境。系统通过显示其执行的指令的结果来与用户通信。它对于开发和调试过程都很方便。REPL的所有部分都有特定的任务。
读取读取用户提供的输入。经过必要的解析后将信息保存在内存中。Eval对解析信息后的数据结构进行求值并生成结果。打印将评估后生成的结果显示给用户。循环以上三个步骤全部循环直到用户按两次ctrlc退出循环。
每个 Node.js 安装都附带 REPL允许即时测试和探索 JavaScript 代码而无需将其保存在文件中。
将其视为一种对话式编码体验。输入代码表达式REPL 会对其进行评估并显示结果可以快速迭代和学习。这使得 REPL 在以下方面具有无价的价值
学习和实验在安全、隔离的环境中尝试新的 JavaScript 功能、探索库并测试假设。调试和故障排除逐行隔离和修复代码中的问题检查每一步的变量和值。交互式开发快速对想法进行原型设计获得即时反馈并迭代优化代码。访问 REPL
打开终端并输入 node。瞧您现在已进入 REPL可以开始游戏了。输入任何 JavaScript 变量赋值、函数调用甚至是复杂的计算。
$ nodeWelcome to Node.js v20.11.0.
Type .help for more information.Math.random()
0.6148448277159013 Hello World
Hello World 1 2 - 5 * (6 / 8) 10
9.25 var x 10
undefinedvar y 5
undefinedz 40
40x * y
50与前面概述的所有强大功能相比REPL 似乎看似简单。然而只有通过亲身体验它的真正价值才会显现出来。作为 Node.js 开发人员接受 REPL 并将其集成到您的工作流程中不仅有益而且必不可少。
命令行快捷键
CommandsDescription向上/向下 键它用于查看命令历史记录和修改以前的命令ctrl d它终止节点 replctrl c它用于终止当前命令ctrl c 两次它终止节点 repltab 键它指定当前命令的列表
结论
REPL 是 Read Evaluate Print Loop的缩写它是一种编程语言环境它接受单个表达式作为用户输入执行它并在执行后将结果返回到控制台。您可以通过在 shell/控制台上输入node来启动 REPL。REPL 允许您快速测试和评估 JavaScript 代码而无需将其保存在文件中。REPL 提供了一些快捷方式尽可能减少编写命令所需的时间。REPL 的行为可以通过某些命令如.break、.clear、.help等控制。你可以在 REPL 中写入算术表达式然后按下 Enter 键即可得到计算结果。您可以以与在 javascript 文件中相同的方式在 REPL 中定义变量。
结论
在 Node.js 提供的强大工具库中工作线程可处理 CPU 密集型任务集群模块可实现水平扩展http2可提供 HTTP/2 网络协议的强大功能流可提供高效的数据处理REPL可实现交互式探索和学习。
通过掌握这些功能您将释放 Node.js 的全部潜力并构建高性能、可扩展且令人愉快的开发体验。