很多人似乎都无法理解单线程 NodeJS 是如何与多线程后端竞争的。
要找出原因,我们必须了解 Nodejs 是单线程的真正含义。
JavaScript 本身最初是为了做一些简单的事情而创建的,比如验证表单、做出响应等,直到 2009 年,Node.js 的创建者 Ryan Dahl 才使使用 JavaScript 编写服务器端代码成为可能。
支持多线程的服务器端语言具有各种结构和构造,用于在线程和其他面向线程的特性之间同步。
支持这些东西意味着 JavaScript 需要改变整个语言,而这也违背了javascript缔造者的想法。因此,为了让纯 JavaScript 支持多线程,Dahl 必须创建一种解决方法。让我们来看看吧!
Node.js 是如何工作的?
Node.js 使用两种线程:由事件循环处理的主线程和工作线程池的几个辅助线程。
事件循环Node.js 处理非阻塞 I/O 操作的机制——尽管 JavaScript 是单线程处理的——当有可能的时候,它们会把操作转移到系统内核中去。当 JavaScript 操作阻塞线程时,事件循环也被阻塞。
工作池是一种执行模型,它产生和处理单独的线程,然后同步执行任务并将结果返回给事件循环。然后事件循环使用所述结果执行提供的回调。
基本上,工作池处理异步 I/O 操作——主要是与系统磁盘和网络的交互。一些模块使用开箱即用的工作池,例如 fs(I/O-heavy)或 crypto(CPU-heavy)。工作池是在 libuv 中实现的,当 Node 需要在 JavaScript 和 C++ 之间内部传输数据时,这会导致轻微的延迟,但几乎可以忽略。
理解了事件循环和工作池的含义之后 我们看下下面代码:
在上面的代码中,我们不必同步等待事件。我们将读取文件的任务委托给工作池,并使用结果调用提供的函数。由于工作池有自己的线程,因此事件循环可以在读取文件的同时继续正常执行。
给大家介绍一下:worker_threads
随着 Node.js 10.5.0 的发布,出现了 worker_threads。它支持在 JavaScript 中创建简单的多线程应用程序
worker_threads 是一个nodejs模块包。线程工作者是在单独线程中生成的一段代码(通常从文件中取出)。
需要注意的是,术语线程工作者、工作者和线程通常可以互换使用。它们都指的是同一件事。
Node.js 中的工作线程对于执行繁重的 JavaScript 任务很有用。在线程的帮助下,Worker 可以轻松地并行运行 JavaScript 代码,从而使其更快、更高效。我们可以在不干扰主线程的情况下完成繁重的任务。
旧版本的 Node.js 中没有引入工作线程。因此,首先更新您的 Node.js 以开始使用。
现在创建两个文件来实现线程,如下所示:
文件名:worker.js
const { workerData, parentPort } = require('worker_threads'); console.log(`Write-up on how ${workerData} wants to chill with the big boys`); parentPort.postMessage({ filename: workerData, status: 'Done' });
文件名:index.js
const { Worker } = require('worker_threads'); const runSerice = (workerData) => { return new Promise((resolve, reject) => { const worker = new Worker('./worker.js', { workerData }); worker.on('message', resolve); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) reject(new Error(`Worker Thread stopped with exit code ${code}`)); }); }); }; const run = async () => { const result = await runSerice('Tunde Ednut'); console.log(result); }; run().catch((err) => console.error(err));
输出: