最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Nodejs 構(gòu)建Cluster集群多線程Worker threads

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

前言

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

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

進(jìn)程間通過傳輸 ArrayBuffer 實(shí)例或共享 SharedArrayBuffer 實(shí)例來做到這一點(diǎn),對(duì)數(shù)據(jù)格式?jīng)]有太多要求。但是要注意,數(shù)據(jù)中不能包含函數(shù)。

Cluster 多進(jìn)程

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

// master.js
const cl = require("cluster");
const cpus = require("os").cpus().length;
// 修改默認(rèn)的 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();
});

子進(jìn)程依舊使用昨天的代碼:

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

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

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

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`);
};

實(shí)現(xiàn)原理

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

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

cluster事件

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

?? 這些事件大多跟 child_process 模塊的事件相關(guān),在進(jìn)程間消息傳遞的基礎(chǔ)上完成的封裝。

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

Worker threads多線程

V8 多線程模型

眾所周知,JavaScript 在運(yùn)行時(shí)是單線程的。但 JavaScript 的 Runtime V8 引擎卻不是單線程的。大致包括以下幾個(gè)線程:

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

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

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

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

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

多線程支持

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

你可以通過下面這段簡單的代碼來體驗(yàn)一下:

// 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
}

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

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

總結(jié)

通過構(gòu)建集群,你能夠充分調(diào)用CPU資源,賦予Node更強(qiáng)勁的性能。而利用多線程模型,將長耗時(shí)的任務(wù)交由子線程來處理,你能合理分配程序運(yùn)行資源。

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

以上就是Nodejs 構(gòu)建Cluster集群多線程Worker threads的詳細(xì)內(nèi)容,更多關(guān)于Nodejs 構(gòu)建Cluster多線程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • node.js Sequelize實(shí)現(xiàn)單實(shí)例字段或批量自增、自減

    node.js Sequelize實(shí)現(xiàn)單實(shí)例字段或批量自增、自減

    Sequelize 可以實(shí)現(xiàn)針對(duì)單個(gè)實(shí)例的一或多個(gè)字段的自增、自減操作,也可以對(duì)符合條件的數(shù)據(jù)進(jìn)行批量的自增、自減操作。單個(gè)實(shí)例字段的自增、自減可以利用Instance的相應(yīng)方法實(shí)現(xiàn),而批量自增、自減則需要借助sequelize提供的字面量方法實(shí)現(xiàn)。下面來看看詳細(xì)的介紹吧。
    2016-12-12
  • Lua表達(dá)式和控制結(jié)構(gòu)學(xué)習(xí)筆記

    Lua表達(dá)式和控制結(jié)構(gòu)學(xué)習(xí)筆記

    這篇文章主要介紹了Lua表達(dá)式和控制結(jié)構(gòu)學(xué)習(xí)筆記,本文講解了算術(shù)操作符、關(guān)系操作符、邏輯操作符、局部變量與作用域、控制結(jié)構(gòu)等內(nèi)容,需要的朋友可以參考下
    2014-12-12
  • 解決使用node命令提示:'node'不是內(nèi)部或外部命令,也不是可運(yùn)行的程序

    解決使用node命令提示:'node'不是內(nèi)部或外部命令,也不是可運(yùn)行的程序

    最近在工作中遇到了個(gè)常見的問題,分享給大家,這篇文章主要給大家介紹了關(guān)于如何解決使用node命令提示:'node'不是內(nèi)部或外部命令,也不是可運(yùn)行的程序的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • Windows安裝Node.js報(bào)錯(cuò):2503、2502的解決方法

    Windows安裝Node.js報(bào)錯(cuò):2503、2502的解決方法

    這篇文章主要給大家介紹了關(guān)于在Windows系統(tǒng)下安裝Node.js報(bào)錯(cuò):2503、2502的解決方法,文中將解決的方法一步步介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10
  • node.js操作mysql簡單實(shí)例

    node.js操作mysql簡單實(shí)例

    本文給大家介紹了nodejs 連接Mysql相關(guān)操作的示例代碼,主要用到的是sql語句,都是比較基礎(chǔ)的。
    2017-05-05
  • 使用pm2運(yùn)行node應(yīng)用的流程步驟

    使用pm2運(yùn)行node應(yīng)用的流程步驟

    PM2是一個(gè)功能強(qiáng)大的進(jìn)程管理工具,專為?Node.js?應(yīng)用設(shè)計(jì),它提供了進(jìn)程管理、日志管理、負(fù)載均衡和性能監(jiān)控等功能,幫助開發(fā)者輕松應(yīng)對(duì)生產(chǎn)環(huán)境中的各種挑戰(zhàn),本文給大家介紹了使用pm2?運(yùn)行node應(yīng)用的流程步驟,需要的朋友可以參考下
    2024-03-03
  • NodeJS實(shí)現(xiàn)圖片文本分割

    NodeJS實(shí)現(xiàn)圖片文本分割

    這篇文章主要為大家詳細(xì)介紹了NodeJS實(shí)現(xiàn)圖片文本分割,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 一步步教你利用Docker設(shè)置Node.js

    一步步教你利用Docker設(shè)置Node.js

    這篇文章主要介紹了利用Docker設(shè)置Node.js的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Nodejs中的JWT和Session的使用

    Nodejs中的JWT和Session的使用

    這篇文章主要介紹了Nodejs中的JWT和Session的使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • nvm如何切換與管理node版本

    nvm如何切換與管理node版本

    這篇文章主要介紹了nvm如何切換與管理node版本問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03

最新評(píng)論

微博| 当涂县| 习水县| 永和县| 芮城县| 达拉特旗| 长葛市| 肥乡县| 阿拉善右旗| 太康县| 武山县| 诸城市| 林甸县| 阿荣旗| 清徐县| 收藏| 鄂托克前旗| 凤庆县| 江口县| 鄢陵县| 正镶白旗| 清苑县| 延庆县| 且末县| 裕民县| 昌平区| 鄢陵县| 偏关县| 平塘县| 登封市| 饶河县| 阿克苏市| 海南省| 新蔡县| 永靖县| 九龙坡区| 阳曲县| 黔西县| 灵武市| 洛川县| 张北县|