欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Nodejs 構建Cluster集群多線程Worker threads

 更新時間:2022年10月21日 11:19:35   作者:SaraiNoQ  
這篇文章主要為大家介紹了Nodejs 構建Cluster集群多線程Worker threads示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

前兩天我們介紹了使用 Nodejs 中的 child_process 模塊創(chuàng)建多個子進程,同時利用進程間通信的API構建了一個集群式的Web服務器。實際上,你可以通過 cluster 模塊更方便的完成這一操作。

但是,cluster 創(chuàng)建的進程之間無法共享內存,通信必須使用 JSON 格式,有一定的局限性和性能問題。如果你不想要進程隔離,可以使用 worker_thread 模塊,它允許在一個 Node.js 實例中運行多個應用程序線程。相比創(chuàng)建多個進程更輕量,并且可以共享內存。

進程間通過傳輸 ArrayBuffer 實例或共享 SharedArrayBuffer 實例來做到這一點,對數(shù)據格式沒有太多要求。但是要注意,數(shù)據中不能包含函數(shù)。

Cluster 多進程

我們可以使用 cluster 模塊提供的API重構昨天的案例:

// master.js
const cl = require("cluster");
const cpus = require("os").cpus().length;
// 修改默認的 fork() 方法配置
cl.setupPrimary({
  exec: 'worker.js'
});
for(let i = 0; i < cpus; i++) {
  cl.fork();
};
cl.on('listening', (data) => {
  console.log(`listenning on: ${data.id}--${data.process.pid}`);
});
cl.on('exit', (data, code, signal) => {
  console.log(`exited: ${data.id}--${data.process.pid}, kill code: $[code], signal: ${signal}`);
  cl.fork();
});

子進程依舊使用昨天的代碼:

const http = require("http");
const server = http.createServer((req, res) => {
  res.writeHead(200, {
    "Content-Type": "text/plain"
  });
  res.end("Hello,World!" + process.pid);
  // 拋出異常,捕獲后終止進程
  throw new Error('throw exception');
}).listen(1337);
// 捕獲異常后終止進程
process.on('uncaughtException', (err) => {
  // 停止接收新的連接
  server.close((data) => {
    console.log(`worker: ${process.pid} is stopping!`);
    process.exit(1);
  })
  // 避免長連接請求長時間無法終止,5s后自動終止
  setTimeout(() => {
    process.exit(1);
  }, 5000)
});

執(zhí)行 node master.js,會得到與昨天利用 child_process 模塊創(chuàng)建子進程集群相同的效果。

同樣,你可以使用官方推薦的寫法,利用 cluster.isPrimary 和 cluster.isWorker 來判斷當前進程是否為主進程:

const cluster = require('node:cluster');
const http = require('node:http');
const numCPUs = require('node:os').cpus().length;
const process = require('node:process');
if (cluster.isPrimary) {
  console.log(`Primary ${process.pid} is running`);
  // Fork workers.
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  // In this case it is an HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(1337);
  console.log(`Worker ${process.pid} started`);
};

實現(xiàn)原理

事實上,cluster 模塊就是將 child_processnet 模塊的API組合起來實現(xiàn)的。cluster啟動時,進程會在內部啟動TCP服務器。而在調用 cluster.fork() 復制子進程時,會將這個TCP服務器端 Socket 的句柄發(fā)送給工作進程。如果進程是通過 cluster.fork() 復制出來的,那么它的環(huán)境變量里就存在 NODE_UNIQUE_ID。如果工作進程中存在 listen() 偵聽網絡端口的調用,它將拿到該句柄,再通過 SO_REUSEADDR 端口重用,從而實現(xiàn)多個子進程共享端口。對于正常方式啟動的進程,則不存在句柄共享和傳遞等過程。

cluster 內部隱式創(chuàng)建TCP服務器的方式對使用者是透明的,你不需要自己手動去實現(xiàn)句柄的傳遞,但也正是因此,它無法像使用 child_process 那樣靈活。在 child_process 中你可以自行控制句柄的傳送,因此可以靈活地控制工作進程,甚至控制多組工作進程。

cluster事件

  • Event: disconnect 主進程和工作進程之間IPC通道斷開后會觸發(fā)該事件。
  • Event: exit 有工作進程退出時觸發(fā)該事件。
  • Event: fork 復制一個工作進程后觸發(fā)該事件。
  • Event: listening 工作進程中調用 listen() 后,發(fā)送該消息給主進程,主進程收到后,觸發(fā)該事件。
  • Event: message
  • Event: online fork好一個工作進程后,工作進程主動發(fā)送該消息給主進程,主進程收到消息后,觸發(fā)該事件。
  • Event: setup .setupPrimary() 方法執(zhí)行后觸發(fā)

?? 這些事件大多跟 child_process 模塊的事件相關,在進程間消息傳遞的基礎上完成的封裝。

使用 Node 構建集群能夠充分利用多核CPU的計算性能,而 child_process 模塊的進程間通信和多種事件能夠極大提升Node的穩(wěn)定性。但進程間無法共享資源,進程間通信有局限性和性能問題。此時就需要引入更輕量級的線程了。

Worker threads多線程

V8 多線程模型

眾所周知,JavaScript 在運行時是單線程的。但 JavaScript 的 Runtime V8 引擎卻不是單線程的。大致包括以下幾個線程:

  • JavaScript 主線程:編譯、執(zhí)行代碼。
  • 編譯線程:當主線程在執(zhí)行時,編譯線程可以優(yōu)化代碼。
  • Profiler 線程:記錄方法耗時的線程。
  • 其它線程:比如支持并行 GC 的多線程。
  • libuv線程池,默認四個線程,全局共享,可以將異步操作和計算密集任務交給它執(zhí)行。

對于 Node 來說,crypto 這種 CPU 密集 和 fs 這種 I/O 密集的任務是在 libuv線程池 中進行的。其執(zhí)行模型是單獨創(chuàng)建一個進程,在這個進程中同步執(zhí)行任務,然后將結果返回到 Event Loop 中,Event Loop 可以通過回調函數(shù)獲取并使用結果。

const fs = require("fs");
fs.writeFile('./target.txt', 'hello Node.js', (err) => {
  if (err) throw err;
  console.log('文件已被保存');
});

使用非阻塞方法,長耗時的方法不會阻塞主進程之后的代碼,只需告訴 Worker Pool 去執(zhí)行該命令,并將結果返回給預先設置好的回調函數(shù),在計算完成時觸發(fā)即可。

?? 由于 Worker Pool 運行在 libuv線程池 中,主線程的 Event Loop 不會被阻塞。能夠充分利用 CPU 資源。

多線程支持

Node v10.5.0 提供了 Worker threads 模塊,開始支持多線程編程。在創(chuàng)建出的每個工作線程中,都會包含 V8 和 libuv,即都包含Event Loop:

你可以通過下面這段簡單的代碼來體驗一下:

// main.js
const { Worker, isMainThread } = require('worker_threads');
if (isMainThread) {
  console.log("I'm main thread: ", isMainThread);
  // create subThread
  new Worker(__filename);
}
else {
  console.log("I'm not main thread: ", isMainThread);
  // subThread destroy
}

我們在主線程中調用new方法創(chuàng)建了一個子線程,子線程執(zhí)行完自動銷毀。最后執(zhí)行結果如下:

?? 合理使用子線程,你能充分調用和分配資源。對于有計算密集型需求的應用,這是一個重要的優(yōu)化手段。另外,由于頻繁地創(chuàng)建、銷毀一個線程的開銷很大,你可以創(chuàng)建線程池來解決這個問題。

總結

通過構建集群,你能夠充分調用CPU資源,賦予Node更強勁的性能。而利用多線程模型,將長耗時的任務交由子線程來處理,你能合理分配程序運行資源。

目前為止,我們介紹完了 Node 的網絡、IO、進程模塊,還剩下異步編程和Event Loop兩個重點。另外,今天在看 Node 文檔時發(fā)現(xiàn) Node v19 剛剛發(fā)布了,v18 即將成為穩(wěn)定版

以上就是Nodejs 構建Cluster集群多線程Worker threads的詳細內容,更多關于Nodejs 構建Cluster多線程的資料請關注腳本之家其它相關文章!

相關文章

  • Koa 中的錯誤處理解析

    Koa 中的錯誤處理解析

    這篇文章主要介紹了Koa 中的錯誤處理解析,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-04-04
  • Node.js+Express+Vue+MySQL+axios的項目搭建全過程

    Node.js+Express+Vue+MySQL+axios的項目搭建全過程

    這篇文章主要介紹了Node.js+Express+Vue+MySQL+axios的項目搭建全過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 淺談node模塊與npm包管理工具

    淺談node模塊與npm包管理工具

    這篇文章主要介紹了node模塊與npm包管理工具,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 基于socket.io+express實現(xiàn)多房間聊天

    基于socket.io+express實現(xiàn)多房間聊天

    本文給大家分享的是使用node.js,基于socket.io+express實現(xiàn)多房間聊天的代碼,非常的實用,有需要的小伙伴可以來參考下
    2016-03-03
  • npm全局環(huán)境變量配置詳解

    npm全局環(huán)境變量配置詳解

    這篇文章主要介紹了npm全局環(huán)境變量配置詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • 關于commander.js使用及源碼分析

    關于commander.js使用及源碼分析

    這篇文章主要介紹了關于commander.js使用及源碼分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Node.js中防止錯誤導致的進程阻塞的方法

    Node.js中防止錯誤導致的進程阻塞的方法

    這篇文章主要介紹了Node.js中防止錯誤導致的進程阻塞的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-08-08
  • Nodejs?Docker鏡像體積優(yōu)化實踐詳解

    Nodejs?Docker鏡像體積優(yōu)化實踐詳解

    這篇文章主要為大家介紹了Nodejs?Docker鏡像體積優(yōu)化實踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • node pnpm修改默認包的存儲路徑(操作方法)

    node pnpm修改默認包的存儲路徑(操作方法)

    PNPM是一個新的包管理工具,也是NPM的另一個替代方案,與NPM不同,PNPM使用符號鏈接(symlink)而不是復制文件來安裝包,這篇文章主要介紹了node pnpm修改默認包的存儲路徑,需要的朋友可以參考下
    2024-05-05
  • 如何在Nodejs中使用模塊fs文件系統(tǒng)

    如何在Nodejs中使用模塊fs文件系統(tǒng)

    這篇文章主要介紹了如何在Nodejs中使用模塊fs文件系統(tǒng),對nodejs感興趣的同學,可以參考下
    2021-05-05

最新評論