广告
返回顶部
首页 > 资讯 > 前端开发 > node.js >Nodejs中多线程的操作方法
  • 502
分享到

Nodejs中多线程的操作方法

2024-04-02 19:04:59 502人浏览 安东尼
摘要

这篇文章主要介绍“nodejs中多线程的操作方法”,在日常操作中,相信很多人在nodejs中多线程的操作方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Nodejs中多线程

这篇文章主要介绍“nodejs多线程的操作方法”,在日常操作中,相信很多人在nodejs中多线程的操作方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Nodejs中多线程的操作方法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

本文测试使用环境:
系统:MacOS Mojave 10.14.2
CPU:4 核 2.3 GHz
Node: 10.15.1

从 Node 线程说起

一般人理解 Node 是单线程的,所以 Node 启动后线程数应该为 1,我们做实验看一下。【推荐学习:《nodejs 教程》】

setInterval(() => {
  console.log(new Date().getTime())
}, 3000)

Nodejs中多线程的操作方法

可以看到 Node 进程占用了 7 个线程。为什么会有 7 个线程呢?

我们都知道,Node 中最核心的是 v8 引擎,在 Node 启动后,会创建 v8 的实例,这个实例是多线程的。

  • 主线程:编译、执行代码。

  • 编译/优化线程:在主线程执行的时候,可以优化代码。

  • 分析器线程:记录分析代码运行时间,为 Crankshaft 优化代码执行提供依据。

  • 垃圾回收的几个线程。

所以大家常说的 Node 是单线程的指的是 javascript 的执行是单线程的,但 Javascript 的宿主环境,无论是 Node 还是浏览器都是多线程的。

Node 有两个编译器:
full-codegen:简单快速地将 js 编译成简单但是很慢的机械码。
Crankshaft:比较复杂的实时优化编译器,编译高性能的可执行代码。

某些异步 IO 会占用额外的线程

还是上面那个例子,我们在定时器执行的同时,去读一个文件:

const fs = require('fs')

setInterval(() => {
    console.log(new Date().getTime())
}, 3000)

fs.readFile('./index.html', () => {})

Nodejs中多线程的操作方法

线程数量变成了 11 个,这是因为在 Node 中有一些 io 操作(DNS,FS)和一些 CPU 密集计算(Zlib,Crypto)会启用 Node 的线程池,而线程池默认大小为 4,因为线程数变成了 11。

我们可以手动更改线程池默认大小:

process.env.UV_THREADPOOL_SIZE = 64

一行代码轻松把线程变成 71。

Nodejs中多线程的操作方法

cluster 是多线程吗?

Node 的单线程也带来了一些问题,比如对 cpu 利用不足,某个未捕获的异常可能会导致整个程序的退出等等。因为 Node 中提供了 cluster 模块,cluster 实现了对 child_process 的封装,通过 fork 方法创建子进程的方式实现了多进程模型。比如我们最常用到的 pm2 就是其中最优秀的代表。

我们看一个 cluster 的 demo:

const cluster = require('cluster');
const Http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`主进程 ${process.pid} 正在运行`);
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 已退出`);
  });
} else {
  // 工作进程可以共享任何 tcp 连接。
  // 在本例子中,共享的是 HTTP 服务器。
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('Hello World');
  }).listen(8000);
  console.log(`工作进程 ${process.pid} 已启动`);
}

这个时候看下活动监视器:

Nodejs中多线程的操作方法

一共有 9 个进程,其中一个主进程,cpu 个数 x cpu 核数 = 2 x 4 = 8 个 子进程。

所以无论 child_process 还是 cluster,都不是多线程模型,而是多进程模型。虽然开发者意识到了单线程模型的问题,但是没有从根本上解决问题,而且提供了一个多进程的方式来模拟多线程。从前面的实验可以看出,虽然 Node (V8)本身是具有多线程的能力的,但是开发者并不能很好的利用这个能力,更多的是由 Node 底层提供的一些方式来使用多线程。Node 官方说:

You can use the built-in Node Worker Pool by developing a c++ addon. On older versions of Node, build your C++ addon using NAN, and on newer versions use N-api. node-WEBworker-threads offers a JavaScript-only way to access Node’s Worker Pool.

但是对于 JavaScript 开发者,一直没有一个标准的、好用的方式来使用 Node 的多线程能力。

真 - Node 多线程

直到 Node 10.5.0 的发布,官方才给出了一个实验性质的模块 worker_threads 给 Node 提供真正的多线程能力。

先看下简单的 demo:

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

function mainThread() {
  for (let i = 0; i < 5; i++) {
    const worker = new Worker(__filename, { workerData: i });
    worker.on('exit', code => { console.log(`main: worker stopped with exit code ${code}`); });
    worker.on('message', msg => {
      console.log(`main: receive ${msg}`);
      worker.postMessage(msg + 1);
    });
  }
}

function workerThread() {
  console.log(`worker: workerDate ${workerData}`);
  parentPort.on('message', msg => {
    console.log(`worker: receive ${msg}`);
  }),
  parentPort.postMessage(workerData);
}

if (isMainThread) {
  mainThread();
} else {
  workerThread();
}

上述代码在主线程中开启五个子线程,并且主线程向子线程发送简单的消息。

由于 worker_thread 目前仍然处于实验阶段,所以启动时需要增加 --experimental-worker flag,运行后观察活动监视器:

Nodejs中多线程的操作方法

不多不少,正好多了五个子线程。

worker_thread 模块

worker_thread 核心代码

worker_thread 模块中有 4 个对象和 2 个类。

  • isMainThread: 是否是主线程,源码中是通过 threadId === 0 进行判断的。

  • MessagePort: 用于线程之间的通信,继承自 EventEmitter。

  • MessageChannel: 用于创建异步、双向通信的通道实例。

  • threadId: 线程 ID。

  • Worker: 用于在主线程中创建子线程。第一个参数为 filename,表示子线程执行的入口。

  • parentPort: 在 worker 线程里是表示父进程的 MessagePort 类型的对象,在主线程里为 null

  • workerData: 用于在主进程中向子进程传递数据(data 副本)

来看一个进程通信的例子:

const assert = require('assert');
const {
  Worker,
  MessageChannel,
  MessagePort,
  isMainThread,
  parentPort
} = require('worker_threads');
if (isMainThread) {
  const worker = new Worker(__filename);
  const subChannel = new MessageChannel();
  worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
  subChannel.port2.on('message', (value) => {
    console.log('received:', value);
  });
} else {
  parentPort.once('message', (value) => {
    assert(value.hereIsYourPort instanceof MessagePort);
    value.hereIsYourPort.postMessage('the worker is sending this');
    value.hereIsYourPort.close();
  });
}

更多详细用法可以查看官方文档。

多进程 vs 多线程

根据大学课本上的说法:“进程是资源分配的最小单位,线程是CPU调度的最小单位”,这句话应付考试就够了,但是在实际工作中,我们还是要根据需求合理选择。

下面对比一下多线程与多进程:

属性多进程多线程比较
数据数据共享复杂,需要用IPC;数据是分开的,同步简单因为共享进程数据,数据共享简单,同步复杂各有千秋
CPU、内存占用内存多,切换复杂,CPU利用率低占用内存少,切换简单,CPU利用率高多线程更好
销毁、切换创建销毁、切换复杂,速度慢创建销毁、切换简单,速度很快多线程更好
coding编码简单、调试方便编码、调试复杂多进程更好
可靠性进程独立运行,不会相互影响线程同呼吸共命运多进程更好
分布式可用于多机多核分布式,易于扩展只能用于多核分布式多进程更好

上述比较仅表示一般情况,并不绝对。

work_thread 让 Node 有了真正的多线程能力,算是不小的进步。

到此,关于“Nodejs中多线程的操作方法”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Nodejs中多线程的操作方法

本文链接: https://www.lsjlt.com/news/67244.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Nodejs中多线程的操作方法
    这篇文章主要介绍“Nodejs中多线程的操作方法”,在日常操作中,相信很多人在Nodejs中多线程的操作方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Nodejs中多线程...
    99+
    2022-10-19
  • nodejs中使用多线程编程的方法实例
    在以前的博文别说不可能,nodejs中实现sleep中,我向大家介绍了nodejs addon的用法。今天的主题还是addon,继续挖掘c/c++的能力,弥补nodejs的弱点。 我曾多次提到过nodejs...
    99+
    2022-06-04
    多线程 实例 方法
  • Python3中多线程操作MySQL插入数据的方法
    这篇文章主要介绍Python3中多线程操作MySQL插入数据的方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!多线程(连接池)操作MySQL插入数据针对于此篇博客的收获心得:首先是可以构建连接数据库的连接池,这样可...
    99+
    2023-06-15
  • Shell多线程操作及线程数控制方法教程
    本篇内容主要讲解“Shell多线程操作及线程数控制方法教程”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Shell多线程操作及线程数控制方法教程”吧!需求为了更好的说明问题,我们结合例子讲解,假...
    99+
    2023-06-09
  • Android中实现多线程操作的几种方式
    目录前言 最基础的方式 继承Thread类并实现run()方法 匿名内部类实现Runnable接口callable+FutureTask 线程池 手动创建线程池 使用Executor...
    99+
    2022-11-12
  • C#线程操作常见的操作方法有哪些
    这篇文章主要讲解了“C#线程操作常见的操作方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#线程操作常见的操作方法有哪些”吧!C#线程操作常见的操作方法是什么呢?C#线程操作方法的...
    99+
    2023-06-17
  • Python多线程以及多线程中join()的使用方法
    本篇内容主要讲解“Python多线程以及多线程中join()的使用方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python多线程以及多线程中join()的使用方法”吧!Python多线程与...
    99+
    2023-06-20
  • NodeJS链接MySql数据库的操作方法
    如下所示: //1.用npm命令安装mysql模块 npm install mysql //2.js文件中引入mysql模块 const mysqlModule = require('mysql'); //...
    99+
    2022-06-04
    操作方法 链接 数据库
  • C#多线程之线程中止Abort()方法
    一、简介 Abort()方法用来终止线程,调用此方法强制停止正在执行的线程,它会抛出一个ThreadAbortException异常从而导致目标线程的终止。 二、代码 cla...
    99+
    2022-11-13
  • JAVA多线程中join()方法的使用方法
    虽然关于讨论线程join()方法的博客已经非常极其特别多了,但是前几天我有一个困惑却没有能够得到详细解释,就是当系统中正在运行多个线程时,join()到底是暂停了哪些线程,大部分博客...
    99+
    2022-11-12
  • Python中多线程和线程池的使用方法
    Python是一种高级编程语言,它在众多编程语言中,拥有极高的人气和使用率。Python中的多线程和线程池是其强大的功能之一,可以让我们更加高效地利用CPU资源,提高程序的运行速度。本篇博客将介绍Py...
    99+
    2023-10-12
    python
  • python中多进程和多线程的使用方法
    这篇文章主要介绍了python中多进程和多线程的使用方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。进程和线程进程是系统进行资源分配的最小单位,线程是系统进行调度执行的最小...
    99+
    2023-06-14
  • C#多线程的ResetAbort()方法
    一、简介 Abort方法可以通过跑出ThreadAbortException异常中止线程,而使用ResetAbort方法可以取消中止线程的操作,下面通过代码演示使用 ResetAbo...
    99+
    2022-11-13
  • C#多线程的Join()方法
    一、简介 Join方法主要是用来阻塞调用线程,直到某个线程终止或经过了指定时间为止。官方的解释比较乏味,通俗的说就是创建一个子线程,给它加了这个方法,其它线程就会暂停执行,直到这个线...
    99+
    2022-11-13
  • Nodejs读写文件的操作方法有哪些
    这篇“Nodejs读写文件的操作方法有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Nodejs读写文件的操作方法有哪些...
    99+
    2023-07-04
  • Python多线程以及多线程中join()的使用方法示例
    Python多线程与多进程中join()方法的效果是相同的。 下面仅以多线程为例: 首先需要明确几个概念: 知识点一: 当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流...
    99+
    2022-11-12
  • Java线程同步:实现多线程协作的方法与技巧
    在Java中,多线程编程是非常常见的,但是在多线程编程中,线程之间的同步是一个非常关键的问题。同步是指多个线程在执行过程中,能够协调和互相配合,以达到正确的执行结果。否则,会出现数据不一致、死锁等问题,影响程序的正确性和性能。 本文将介绍...
    99+
    2023-11-09
    同步 numy 日志
  • python多线程线程锁的使用方法
    小编给大家分享一下python多线程线程锁的使用方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!python的数据类型有哪些python的数据类型:1. 数字类...
    99+
    2023-06-14
  • java中多线程与线程池的基本使用方法
    目录前言继承Thread 实现Runnale接口Callable线程池常见的4种线程池。总结前言 在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,服务器...
    99+
    2022-11-12
  • 多线程之线程同步的方法(7种)
    1. 锁机制:使用锁对象对需要同步的代码块进行加锁,确保同一时刻只有一个线程可以执行该代码块。2. 互斥量:使用互斥量(Mutex)...
    99+
    2023-09-15
    多线程
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作