91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Nodejs中多線程的操作方法

發布時間:2021-06-23 11:09:41 來源:億速云 閱讀:4369 作者:chen 欄目:web開發

這篇文章主要介紹“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中多線程的操作方法”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

靖远县| 水城县| 疏附县| 长治县| 江西省| 铅山县| 白城市| 宝清县| 夏河县| 奎屯市| 衡南县| 嫩江县| 平利县| 新乡市| 巴林右旗| 加查县| 鹰潭市| 棋牌| 封丘县| 蒲江县| 望都县| 灌云县| 乐平市| 祁阳县| 永兴县| 嘉禾县| 海阳市| 兴山县| 桐庐县| 巴彦淖尔市| 葫芦岛市| 海兴县| 潼关县| 南充市| 会同县| 合肥市| 高碑店市| 溧水县| 泸定县| 娄底市| 平泉县|