ホームページ > ウェブフロントエンド > jsチュートリアル > Nodejs のマルチスレッド操作に関する簡単な説明

Nodejs のマルチスレッド操作に関する簡単な説明

青灯夜游
リリース: 2021-06-24 11:28:19
転載
4520 人が閲覧しました

nodejs はシングルスレッドですが、マルチスレッド操作が可能です。この記事では、Node スレッドから始まり、Nodejs でのマルチスレッド操作について説明し、worker_threads テンプレートを紹介します。

Nodejs のマルチスレッド操作に関する簡単な説明

この記事のテスト環境:
システム: macOS Mojave 10.14.2
CPU: 4 コア 2.3 GHz
ノード: 10.15 .1

[推奨学習:「nodejs チュートリアル 」]

Node スレッドから始める

ほとんどの人Nodeを理解する シングルスレッドなのでNode起動後のスレッド数は1になっているはずですが、実験してみましょう。 [推奨学習: "nodejs チュートリアル"]

setInterval(() => {
  console.log(new Date().getTime())
}, 3000)
ログイン後にコピー

Nodejs のマルチスレッド操作に関する簡単な説明

Node プロセスが 7 スレッドを占有していることがわかります。なんでスレッドが7つもあるの?

Node のコアは v8 エンジンであることは誰もが知っています。Node が開始されると、v8 のインスタンスが作成されます。このインスタンスはマルチスレッドです。

  • メインスレッド: コードをコンパイルして実行します。
  • コンパイル/最適化スレッド: メインスレッドの実行時に、コードを最適化できます。
  • アナライザー スレッド: 分析コードの実行時間を記録して、クランクシャフトがコードの実行を最適化するための基礎を提供します。
  • ガベージ コレクション用の複数のスレッド。

つまり、Node はシングルスレッドであるとよく言われます。つまり、JavaScript の実行はシングルスレッドですが、Node であれブラウザであれ、JavaScript のホスト環境はマルチスレッドです。ねじ切りされた。

Node には 2 つのコンパイラがあります:
full-codegen: js を単純かつ迅速にコンパイルして、シンプルだが遅いマシン コードを作成します。
Crankshaft: 高性能の実行可能コードをコンパイルする、比較的複雑なリアルタイム最適化コンパイラー。

一部の非同期 IO は追加のスレッドを占有します

上記の例でも、タイマーの実行中にファイルを読み取ります。

const fs = require('fs')

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

fs.readFile('./index.html', () => {})
ログイン後にコピー

Nodejs のマルチスレッド操作に関する簡単な説明

スレッドの数は 11 になります。これは、ノード内に、ノードのスレッド プールを有効にする、いくつかの IO 操作 (DNS、FS) と CPU を大量に使用する計算 (Zlib、Crypto) があるためです。スレッド数が 11 になるため、スレッド プールのデフォルトのサイズは 4 です。

スレッド プールのデフォルト サイズを手動で変更できます:

process.env.UV_THREADPOOL_SIZE = 64
ログイン後にコピー

1 行のコードで簡単にスレッドを 71 に変更できます。

Nodejs のマルチスレッド操作に関する簡単な説明

#cluster マルチスレッドですか?

Node の単一スレッドは、CPU の使用率が不十分である、キャッチされない例外によりプログラム全体が終了する可能性があるなど、いくつかの問題も引き起こします。 Nodeにはclusterモジュールが提供されているため、clusterはchild_processのカプセル化を実装し、forkメソッドで子プロセスを作成することでマルチプロセスモデルを実現します。例えば、私たちがよく使うpm2はその代表格です。

クラスターのデモを見てみましょう:

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(&#39;exit&#39;, (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 已退出`);
  });
} else {
  // 工作进程可以共享任何 TCP 连接。
  // 在本例子中,共享的是 HTTP 服务器。
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(&#39;Hello World&#39;);
  }).listen(8000);
  console.log(`工作进程 ${process.pid} 已启动`);
}
ログイン後にコピー

この時点で、アクティビティ モニターを見てください:

Nodejs のマルチスレッド操作に関する簡単な説明

9 つのプロセスがあります合計、メインプロセス、CPU 数 x CPU コア数 = 2 x 4 = 8 つの子プロセス。

つまり、child_process もクラスタもマルチスレッド モデルではなく、マルチプロセス モデルになります。開発者はシングル スレッド モデルの問題を認識していますが、問題を根本的に解決するわけではなく、マルチ スレッドをシミュレートするマルチプロセス メソッドを提供しています。前の実験から、Node (V8) 自体にはマルチスレッド機能がありますが、開発者はこの機能をうまく活用できず、代わりに Node の最下位層によって提供される何らかの方法でマルチスレッドを使用していることがわかります。 Node 公式は次のように述べています:

C アドオンを開発することで、組み込みの Node Worker Pool を使用できます。古いバージョンの Node では、NAN を使用して C アドオンを構築し、新しいバージョンでは N-API を使用します。 .node-webworker-threads は、Node のワーカー プールにアクセスするための JavaScript のみの方法を提供します。

しかし、JavaScript 開発者にとって、Node のマルチワーカー プールを使用するための標準的で使いやすい方法はこれまでありませんでした。スレッド機能。

True - ノードのマルチスレッド

Node 10.5.0 のリリースまで、公式は実験的なモジュール worker_threads を Node Provides true に提供しました。マルチスレッド機能。

最初に簡単なデモを見てみましょう:

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

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

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

if (isMainThread) {
  mainThread();
} else {
  workerThread();
}
ログイン後にコピー

上記のコードは、メイン スレッドで 5 つのサブスレッドを開き、メイン スレッドは単純なメッセージをサブスレッドに送信します。

由于 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(&#39;assert&#39;);
const {
  Worker,
  MessageChannel,
  MessagePort,
  isMainThread,
  parentPort
} = require(&#39;worker_threads&#39;);
if (isMainThread) {
  const worker = new Worker(__filename);
  const subChannel = new MessageChannel();
  worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
  subChannel.port2.on(&#39;message&#39;, (value) => {
    console.log(&#39;received:&#39;, value);
  });
} else {
  parentPort.once(&#39;message&#39;, (value) => {
    assert(value.hereIsYourPort instanceof MessagePort);
    value.hereIsYourPort.postMessage(&#39;the worker is sending this&#39;);
    value.hereIsYourPort.close();
  });
}
ログイン後にコピー

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

多进程 vs 多线程

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

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

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

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

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

更多编程相关知识,请访问:编程视频!!

以上がNodejs のマルチスレッド操作に関する簡単な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート