Node.js中的Worker Threads小白帮助_Worker小白入门

想要明白workers,首先需要明白node是怎样构成的。当一个node进程开始,它其实是:一个进程。一个线程。一个事件轮垂。一个js引擎实例。一个node.js实例。一个进程:是指一个全局对象,这个对象能够访问任何地方,并且包含当前处理时的此时信息。一个线程:单线程意味着单位时间内只有一组指令在给定的进程中执行。一个事件轮垂:这是理解Node最重要的概念。

Node.js中的Worker Threads小白帮助

想要明白workers,首先需要明白node是怎样构成的。当一个node进程开始,它其实是:

Node.js中的Worker Threads小白帮助_Worker小白入门

  1. 一个进程。
  2. 一个线程。
  3. 一个事件轮垂。
  4. 一个js引擎实例。
  5. 一个node.js实例。

一个进程:是指一个全局对象,这个对象能够访问任何地方,并且包含当前处理时的此时信息。

一个线程:单线程意味着单位时间内只有一组指令在给定的进程中执行。

一个事件轮垂:这是理解Node最重要的概念。它使Node更够异步以及拥有无锁定I/O。即使js是单线程的,通过提供一些系统核心的操作像是回调函数,promise函数以及异步的async/await函数这些功能。

一个JS引擎实例:这是个计算机程序,用来执行js的代码。

一个Node.js实例:一个计算机程序用来执行node.js的代码。

一句话,Node运行在一个单线程上,每次事件轮垂只有一个进程存在。一个代码一次执行(不是并行执行)。这个非常重要,因为它很简单,你不用考虑并发的问题。

这么设计的原因是因为js生出来最初是用来开发客户端交互的(像是页面交互,表单这些),没有对线程这种用复杂的需求。

但是,和所有的事情一样,这样也有缺点:如果你有cpu敏感的代码,例如内存中有大量的来回计算的复杂数据,那么这能锁住其他需要进行处理计算的任务。像是,你向服务器发起一个请求,应对这个请求的接口有cpu敏感的代码,那么它就能锁定事件轮垂进而阻止其他请求的处理(笔者:其实就是其他请求就需要长时间排队甚至超时)。

如果主事件轮垂必须等待一个函数执行完成然后才能执行其他命令,那么这个函数就是“锁定中”。一个无锁定函数会允许主事件轮垂从开始就持续地运行,并且在其执行完成时通知主事件轮垂调用回调函数。

黄金准则:不要锁定事件轮垂,尽量关注和避免那些可能造成锁定的任务,像是同步网路调用或者无线死循环。

明白cpu操作和i/o操作是很重要的。如上所讲,Node中的代码不能并行执行。只是i/o是并行,因为他们是异步执行的。

所以,worker线程(以下我们会使用这个node特有的概念)不能提升多少i/o敏感的任务,因为异步i/o本身就比worker高效很多。worker的主要任务是提升cpu敏感操作的性能。

已有的解决方案

此外,这里已经有一些应对cpu敏感处理的方案:多进程(例如,cluster API)来保证cpu最大被利用。

这个方法好处是允许每个进程间是独立的,如果某个线程出了问题,不会影响到其他的。他们稳定且相同的api。然而,这意味着牺牲了内存共享,并且数据通信必须用json(有额外开销,性能稍低)。

JavaScript和Node.js是永远不会有多线程的。原因如下:

so,有人或许会考虑给node.js添加一个新的模块来允许我们创建一个同步线程,以此来解决cpu敏感处理的问题。

然而,这不会实现的。如果添加一个线程,这个语言的本质就会发生变化。使用类或者函数添加一个线程作为新特性是不可能。在支持多线程的语言中(如java),“synchronized”之类的关键字就能帮助实现多线程。

还有,一些数据不是原子的,意味着如果你不是同步处理他们,你可能的结果是在两个线程上都可以访问并更改这个值得变量,最后得到一个两个线程都对这个者进行了一些改变的无效的值。例如一个简单的0.1+20.2的操作,这个操作拥有17为小数。

因为小数点不是100%准确的,所以如果不是同步的,有一个整数可能使用worker之后得到一个非整数的数字。

最好的解决方案是

提高cpu性能的最好的方案是使用worker线程。浏览器很早既有了worker这个概念了。

使亿有的结构从:

一个进程

一个线程

一个事件轮垂

一个JS隐情实例

一个Node.js实例

变成:

一个进程

多个线程

每个线程一个事件轮垂

每个线程一个JS隐情实例

每个线程一个Node.js实例

worker_threads模块能够实现使用线程实现并行执行js。

const worker = require('worker_threads');

Worker Theads在Node.10时开始可以使用,但是一直处于实验状态,在12.11.0时,变成稳定版本。

这个方案的意思是,在一个进程中拥有多个Node.js的实例。在worker threads中,一个线程可以有一些节点,这个节点不必是父进程。worker结束后还被分配着一些资源不是好的实践,这会导致内存泄漏。我们想把node.js整个的潜入其中,并且给与Node.js去创建新的现成的能力,然后在线程中创建一个新的Node.js实例。本质上是独立运行在一个进程中的线程中。

下面这些使Worker Theads与众不同:

ArrayBuffers在线程间传递内存。
SharedArrayBuffer每个线程都可访问,在线程间分享内存。(只限二进制数据)。
Atomics已可用,允许你并行执行一些处理,更高效且允许你在js中实现条件变量。
MessagePort,用来在不同线程间进行通信。可以用来传递结构数据,内存域,以及不同Worker之间的MessagePort(对象)。
MessageChannel代表一个异步的,双向通信的频道,用来在不同的(worker)线程间通信。
WorkerData用来传递起始数据。任意js数据的复制版本会被传递到这个Worker的构造函数中。如果使用postMessage(),数据也会被复制。

接口API

  • const {worker, parentPort} = require(‘worker_threads’),worker类表示一个独立执行js的线程,parentPort是一个message port的实例。
  • 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’ }

这段代码实际做的是使用new Worker创建了一个线程,在线程的内部使用parentPort来监听和接受一次性的message信息,接收到信息后也会发布一个message个猪线程。

在只支持实验性worker thread的node版本中你必须使用–experimental-worker命令行选项来执行代码。

其他例子:

const {
      Worker, isMainThread, parentPort, workerData
    } = require('worker_threads');

    if (isMainThread) {
      module.exports = function parseJSAsync(script) {
        return new Promise((resolve, reject) => {
          const worker = new Worker(filename, {
            workerData: script
          });
          worker.on('message', resolve);
          worker.on('error', reject);
          worker.on('exit', (code) => {
            if (code !== 0)
              reject(new Error(`Worker stopped with exit code ${code}`));
          });
        });
      };
    } else {
      const { parse } = require('some-js-parsing-library');
      const script = workerData;
      parentPort.postMessage(parse(script));
    }

需要依赖:
Worker该类代表一个独立的js执行线程。
isMainThead一个布尔值,当前代码是否运行在Worker线程中。
parentPortMessagePort对象,如果当前线程是个生成的Worker线程,则允许和父线程通信。
workerData一个可以传递给线程构造函数的任何js数据的的复制数据。

在实战中,上面的任务最好使用线程池来替代。否则,开销可能大于好处。

对Worker的期望是什么(希望是):

  • 传递本地处理任务。(passing native handles around)
  • 锁死检测。锁死是指一种情形,一系列进程被锁定,因为每个进程都把持了一些资源,而且每个线程又在等待其他线程所把持的资源释放然后获取。锁死检测在worker thead中比较有用。
  • 更多的隔离,所以一旦一个线程收到了影响,其他的没事。

对Worker不期望的是:

  • 不要认为worker会使所有的东西都很快速,有些情况下最好使用线程池。
  • 不要使用worker来进行io并行操作。
  • 不要认为衍生一个线程成本很低。

最后:

Workers有chrome开发工具,可用来监视Node.js中的workers。

海计划公众号
(0)
上一篇 2020/03/23 18:38
下一篇 2020/03/23 18:38

您可能感兴趣的内容

  • 程序员,你该如何选择技术方向?小白知识_技术零基础入门

    1、困惑的提问昨天,读者小何在微信上问了我这样一个问题:二哥,我刚参加工作一年,感觉什么也不精通。大学学的是 Java,但这一年来 Python 特别火,有几个转到 Python 的同学工资竟然比我高。我是不是也应该转呢?类似这样的问题还有一些,比如说阿坚:“我现在大一,学的是 C++,听说毕业后不太好找工作,二哥什么好的建议吗?”对于初入职场或者在校的同学

    2020/03/26
  • 男生怎样做容易追到女生,帮你快速追上女神基础知识入门_福利菜鸟教程下载

    小编教你快速追上你的女神。一起来学习一下吧!首先,在你决定追女生之前先要确认她有没有男朋友然后还要了解女生的星座、爱好、三围、喜欢的偶像以及喜欢吃些什么等问题调查完之后就开始追记住一定要做到三点坚持不要脸坚持不要脸这些事情完成后,就开始去追吧!1制造偶遇 ​从她身边的人下手。收拢她的好朋友,知道她随时爱去哪里,来制造偶遇.2.帮助她解决生活中的一些事情

    2020/03/23
  • Logopond使用指南_一款LOGO 设计欣赏的网站

    Logopond小白基础 官方网址:https://logopond.com/ 简介描述:一款LOGO 设计欣赏的网站 logopond是全球最大的logo分享平台,藏标网为大家提…

    2020/03/06
  • Web服务器之Nginx指南教程_nginx小白攻略

    NginxNginx是一个高性能的HTTP和反向代理web服务器,同时也提供IMAP/POP3/SMTP服务。其特点是占有内存少,并发能力强。如果我们在项目中用到了Nginx,那么可以用如下的示意图表示:在这样的一个架构当中,Nginx就被叫做负载均衡服务器或者是反向代理服务器,所有的请求首先会被Nginx给拦截到,然后再由Nginx根据之前配置好的转发规则

    2020/03/23
  • 将规则集传递给mixin小白攻略_mixin基础知识教程

    允许包装在mixin中定义的css块。分离的规则集是一组CSS属性、嵌套规则集、媒体声明或者是存储在变量中的任何其他内容,我们可以将它包含在规则集中或其他结构中,并且所有属性都将复制到那里;我们还可以将它用作mixin参数,并将它作为其他任何变量传递。 // 声明分离的规则@rule_set: { color: green; };// 使用分离的规则集

    2020/03/23
  • Grabient入门教程_生成漂亮的 css 渐变

    Grabient入门教程 官方网址:https://www.grabient.com/ GitHub:https://github.com/johnkorzhuk/grabient…

    2020/03/11
  • 了解HTML及运行原理小白攻略_html基础入门

    了解HTMLHTML(HyperText Marked Language)即超文本标记语言,是一种用来制作超文本文档的简单标记语言。我们在浏览网页时看到的一些丰富的影像、文字、图片等内容都是通过HTML表现出来的。用HTML编写的超文本文档称为HTML文档,它能独立于各种操作系统平台,一直被用作WWW(万维网)的信息表示语言。对于网站软件开发人员来讲,如果不

    2020/03/24
  • limejs基础知识教程_开发现代触控设备与桌面浏览器上本地化体验游戏的HTML5框架

    limejs基础知识教程 官方网址:http://www.limejs.com GitHub:https://github.com/digitalfruit/limejs 简介描述…

    2020/03/06
  • 前端工程之CDN部署基础入门前端为什么非要动静分离?说一下CDN托管的意义_CDN入门攻略

    大型Web应用对速度的追求并没有止步于仅仅利用浏览器缓存,因为浏览器缓存始终只是为了提升二次访问的速度,对于首次访问的加速,我们需要从网络层面进行优化,最常见的手段就是CDN(Content Delivery Network,内容分发网络)加速。通过将静态资源缓存到离用户很近的相同网络运营商的CDN节点上,不但能提升用户的访问速度,还能节省服务器的带宽消耗,

    2020/04/05
  • lazyload.js教程视频_jquery图片懒加载插件

    lazyload.js教程视频 官方网址:https://appelsiini.net/projects/lazyload GitHub:https://github.com/tu…

    2020/03/06
  • layui小白攻略一款采用自身模块规范编写的情怀型前端UI框架

    layui基础入门 官方网址:http://www.layui.com/ GitHub:https://github.com/sentsin/layui/ 简介描述:一款采用自身模…

    2020/03/05
  • 值得推荐的 Docker 安全开源工具教程视频_Docker菜鸟知识

    在容器安全方面,有很多使用开源工具阻止安全灾难的故事,例如前不久发生的特斯拉 Kubernetes 集群入侵事件。容器的安全性一直是一件很棘手的事情,因此如何巧妙使用开源工具就成为一件重要的事情。如果你已经花了大量精力找到了最佳的应用程序安全性测试工具,并确保你的应用程序尽可能安全,那么你肯定不希望运行它的容器是不够安全的。幸运的是,除了商业版的容器安全产品

    2020/03/22
  • LostGrid使用帮助_一个内置于PostCSS的强大网格系统

    LostGrid使用帮助 官方网址:http://lostgrid.org GitHub:https://github.com/peterramsing/lost 简介描述:一个内…

    2020/03/06
  • NodeJs 实现简单WebSocket 即时通讯入门攻略_通讯小白攻略

    服务器的实现很简单,先装一个nodeJs的模块,叫nodejs-websocket , 直接在nodeJs命令行中敲入:npm install nodejs-websocket回车就可以安装好了,然后就可以开始建立服务器了,因为有了nodejs-websocket模块,所以很多工作都不用我们自己做,直接调用别人封装好的方法就行了: 服务端代码根据客户端传来

    2020/03/26
  • Node.js中的路径问题基础知识_路径入门基础教程

    在前端学习过程中,涉及到路径的问题非常多,相对路径,绝对路径等。有时候明明觉得没问题,但是还是会出错。或者说线下没问题,但是到了线上就出现问题,因此弄懂路径问题,非常关键。我们需要知道为什么这个地方既可以使用相对路径,又可以使用绝对路径,为什么有些地方只能使用绝对路径。一、Node.js中加载模块的路径设置const myClass = require(‘.

    2020/03/30
  • 一个完整URL的组成基础指南_url入门百科

    一、什么是URL/URN/URIURI=URL+URNURI:统一资源标识符URL:统一资源定位符URN:统一资源名称二、传输协议用来传输客户端和服务器端交互的信息的(类似于快递小哥)HTTP(顺丰):超文本传输协议(除了传递普通的文本,还可以传递文件流或者进制编码等信息),是目前最常用的WEB传输协议HTTPS(邮政):基于SSL(Secure Socke

    2020/03/23