javascript 执行 命令-了解 Node.js 中的工作线程

本文翻译自LizParody在NodeSource上发表的文章UnderstandingWorkerThreadsinNode.js

要理解Worker(工作线程)的概念,需要了解Node.js的组成:

也就是说,Node是在单线程上执行的javascript 执行 命令,同时,事件循环上只有一个进程、一段代码、一次执行(代码很难并行执行)。 这特别有用,因为它简化了编写 JavaScript 代码的过程,因为您不需要考虑并发性。

之所以采用这些方式构建,是因为 JavaScript 最初是为客户端交互(例如网页交互和表单验证等)而构建的,不需要复杂的多线程模型。

但与其他所有事情一样,这会带来一个问题:如果您正在执行一段 CPU 密集型代码,例如对视频内存中的大型数据集进行复杂计算,它会阻塞其他即将执行的代码。 同样,如果您向服务器端 CPU 密集型 API 发出请求,此代码将阻塞风暴循环并导致服务无法响应其他请求。

如果主风暴循环必须等待某个函数完成执行才能执行下一条指令,则该函数将被阻塞。 非阻塞函数允许主风暴循环在函数开始执行后继续执行后续代码,直到函数完成并通知主风暴循环执行反弹。

黄金法则:不要阻塞风暴循环,让它尽可能长时间地运行,注意并防止任何可能阻塞线程的代码javascript 执行 命令,例如同步网络调用和大量同步循环。

对于开发人员来说,能够区分什么是CPU操作和什么是I/O操作非常重要。 前面提到,Node.js 代码不是并行执行的,但是 I/O 操作可以并发执行,它们都是异步的。 因此,Worker Threads不会改善I/O密集型代码,而主要改善CPU密集型操作的性能。

解决方案

对于CPU密集型操作已经有一些解决方案:使用多进程(集群模块)来提高系统中的CPU利用率。

这种方案的优点是显而易见的,它可以隔离进程,因此一个进程中的任何问题都不会影响其他进程。 不过,这也意味着它们之间很难共享显存,数据通信也必须通过JSON进行序列化。

命令执行常见的场景有哪些_命令执行漏洞的危害_javascript 执行 命令

人们开始构想在 Node.js 中添加一个新的模块来支持线程的创建并实现线程之间的同步,从而解决了 CPU 密集估计的问题。 然而,现实不会是这样的。 如果添加多线程模型,将直接改变JavaScritp语言的本质,而不是简单地添加几个类和函数。

最佳解决方案

CPU性能的最佳解决方案是工作线程,浏览器很早就采用了这些解决方案。

与上面提到的Node.js的组成,即一个进程+一个线程+一个风暴循环+一个JS引擎+一个Node.js实例不同,工作线程的形式是一个进程+多个线程+各一个时间每个线程循环 + 每个线程一个 JS 引擎 + 每个线程一个 Node.js 实例。 大家可以参考下面的对比图:

javascript 执行 命令_命令执行常见的场景有哪些_命令执行漏洞的危害

Node 中的worker_threads 模块提供了同时运行多个JavaScript 线程的能力。 可以通过以下方式导入:

const worker = require('worker_threads');

从 Node.js 10 开始就引入了工作线程,但目前还处于实验阶段,需要启用 --experimental-worker 选项(Node.js 12 可以在不启用该选项的情况下使用)。

理想的情况是在同一个进程中拥有多个 Node.js 实例。

使用工作线程时,线程的结束不会影响主进程,但是当工作线程结束时,如果该线程分配的系统资源被Hang持有,这会导致显存泄漏,这是我们不希望的。

javascript 执行 命令_命令执行常见的场景有哪些_命令执行漏洞的危害

我们想要的是将 Node.js 嵌入其中,让 Node.js 能够创建新线程并在其中创建 Node.js 的新实例,所有这些都在同一进程中的单独线程上运行。

与工作线程相关的概念如下:

工作线程提供的主要API如下:

例子:

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' }

上面的代码通过new Worker()创建了一个新的工作线程。 该线程的代码会监听父线程的消息,一旦接收到消息,消息本身就会被发送回父线程。

如果您使用 Node.js 10,请不要忘记添加 --experimental-worker 选项

对工作线程的一些合理期望:

对工作线程的不合理期望:

此外,Chrome DevTools 支持 Node.js 中的工作线程。 工作线程是 Node.js 中一个很有前途的实验模块。 如果你的Node程序需要处理CPU密集型任务,那么不建议在生产环境中使用工作线程。 您可以考虑使用进程池来代替。