【程式語言 - NodeJS】 worker-threads

閱讀時間約 9 分鐘
早期的 nodejs 為了具有多線程的能力而引入了 cluster 模組, 但這種創建線程的方式會犧牲共享內存, 且數據通信必須透過 json 來傳輸, 因此具有一定的侷限性及性能問題。
而後發展了worker-threads這個模組之後, 具備共享內存的功能, 使其更輕量。
nodejs 在v10.5.0時引入了新的模組worker_threads, 但當時還處於實驗階段, 因此執行程式時需加入參數--experimental-worker才能正確引入該模組, 不過以下實驗採用v12.7.0, 已經不需要額外參數--experimental-worker來開啟模組開關了。

架構

以下的架構圖中, 將從 main.js 中分派可並行的工作給 worker.js 去進行執行, 而 worker.js 在 nodejs 背後的機制相當於 multi threads。
         | ->  worker.js
main.js -| -> worker.js
| -> worker.js

main 與 worker 之間的資料傳遞

  1. 傳遞數據的方式: worker.postMessage(value)。
  2. 接收對方傳遞數據的方式: worker.on('message', callbackFn)。
main.js:
const worker = new Worker('./worker.js');

// 傳遞資料給worker
worker.postMessage('send to worker');
// 監聽: 接收worker回報的資料
worker.on('message', msg => {
console.info(msg);
});
worker.js
import { parentPort } from 'worker_threads';
parentPort.on('message', value => {
console.info(value);
parentPort.postMessage('report to master');
});

實驗

以下範例將實驗相同的運算之下使用單線程與多線程所耗費的時間比較。
題目: 我們會設計有 N 個 worker, 每個 worker 執行 X 次的累加, 每次的累加數字為 Y。
  1. 參數配置:
// 假設8個worker
const workerNum: number = 8;
// 每個worker都做10億次的累加
const perWorkerAccSize: number = 1000000000;
// 每次的累加數字8
const perAccNum: number = 8;
2. 首先我們設計一個累加的函數, 可帶入數字及累加的次數。
const accumulate = (num: number, size: number): number => {
let result: number = 0;
for (let i = 0; i < size; i++) {
result += num;
}
return result;
};
3. 接著我們撰寫單線程的程式:
(() => {
console.info('start accmulate with single...');
const size = workerNum * perWorkerAccSize;
console.info(`do ${size} number to accumulate`);
const start = new Date().getTime();
const sum = accumulate(perAccNum, size);
const end = new Date().getTime();
console.info(`sum: ${sum}, time: ${end - start}`);
})();
4. 設計分派的程式:
/**
* 分派工作
* @param workerNum 工人數量
* @param accNum 每次加總的數字
* @param size 加總的次數
*/
const accWithWorker = async (workerNum: number, accNum: number, size: number): Promise<number> =>
new Promise((resolve, reject) => {
// 紀錄工作做完的次數
let doingCount = 0;
// 總共做完的工作數量
const doneCount = workerNum;
// 加總的最終數量
let sum = 0;
while (--workerNum >= 0) {
console.info(`worker ${workerNum}, do ${size} number to accumulate`);
const worker = new Worker('./dist/worker.js');
// 傳遞加總的數字及次數給worker
worker.postMessage({
accNum,
size
});
// 監聽: worker回報的加總結果
worker.on('message', num => {
sum += num;
if (++doingCount === doneCount) {
resolve(sum);
}
});
}
});
5. 接著最後我們設計每個worker進行加總的工作。
import { parentPort } from 'worker_threads';
parentPort.on('message', (value) => {
const { accNum, size} = value;
parentPort.postMessage(accumulate(accNum, size));
});

const accumulate = (num: number, size: number): number => {
let result: number = 0;
for (let i = 0; i < size; i++) {
result += num;
}
return result;
};

運行結果

可以發現到我們開8個worker進行處理, 時間節省了1/3。
start accmulate with single...
do 8000000000 number to accumulate
sum: 64000000000, time: 9224
start accmulate with 8 worker...
worker 7, do 1000000000 number to accumulate
worker 6, do 1000000000 number to accumulate
worker 5, do 1000000000 number to accumulate
worker 4, do 1000000000 number to accumulate
worker 3, do 1000000000 number to accumulate
worker 2, do 1000000000 number to accumulate
worker 1, do 1000000000 number to accumulate
worker 0, do 1000000000 number to accumulate
sum: 64000000000, time: 2464
為什麼會看到廣告
113會員
254內容數
哈囉,我是阿Han,是一位 👩‍💻 軟體研發工程師,喜歡閱讀、學習、撰寫文章及教學,擅長以圖代文,化繁為簡,除了幫助自己釐清思路之外,也希望藉由圖解的方式幫助大家共同學習,甚至手把手帶您設計出高品質的軟體產品。
留言0
查看全部
發表第一個留言支持創作者!
阿Han的沙龍 的其他內容
概念: 有限時間內可使用通行證來要求對應的操作權限。 JWT 的組成內容有三個部分,由 . 做區隔,最後透過這三個部分,串成一個 Jwt 字串 [HEADER].[PAYLOAD].[SIGNATURE] 1. Header: 主要記載認證的方法 {     "typ": "JWT",     "
概念: 有限時間內可使用通行證來要求對應的操作權限。 JWT 的組成內容有三個部分,由 . 做區隔,最後透過這三個部分,串成一個 Jwt 字串 [HEADER].[PAYLOAD].[SIGNATURE] 1. Header: 主要記載認證的方法 {     "typ": "JWT",     "
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
在一次五天的年假中,我決定開始學習Python編程。雖然最初進展順利,但後來發現自己在解題和邏輯方面遇到了困難。經過思考後,我決定轉而學習C/C++,並且制定了一個計畫,希望成為一名後端工程師。這將需要挑戰我的時間管理能力。
Thumbnail
關於程式語言的學習,只要掌握住幾個基本特性要熟悉幾種程式語言也不困難,這三個基本特性就是…
Thumbnail
對許多駕駛而言,「路邊停車」絕對是最難克服的課題。而這次由比利時遊戲團隊Happy Volcano製作的小品遊戲《You Suck at Parking》,就是要讓玩家體驗到,路邊停車是有多麼困難的事情!
Thumbnail
而這次要介紹的這款遊戲《靈魂連結Soul Link》,是從俄羅斯方塊的機制衍生的造橋遊戲!?
Thumbnail
在近期,我在Steam發現了兩款挺不錯的自動攻擊Roguelite清版遊戲,其中一款是由Night Owls所製作的《Biters & Bullets》,另一款則是本篇文章要介紹的《靈魂石倖存者Soulstone Survivors》!
Thumbnail
在近期,我在Steam發現了兩款挺不錯的自動攻擊Roguelite清版遊戲,而其中一款,是由Night Owls所製作的《Biters & Bullets》,與其他類似遊戲不同的是,這是一款自動攻擊的Roguelite清版「射擊遊戲」!
Thumbnail
這個主題,主要是發表我對一款遊戲作品的前期試玩體驗的感想,裡面會有大量的個人主觀觀點,想跟你分享我試玩這款遊戲的心得。 本次試玩的作品為,由RAYKA STUDIO推出的遊戲作品《太古之火》。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
在一次五天的年假中,我決定開始學習Python編程。雖然最初進展順利,但後來發現自己在解題和邏輯方面遇到了困難。經過思考後,我決定轉而學習C/C++,並且制定了一個計畫,希望成為一名後端工程師。這將需要挑戰我的時間管理能力。
Thumbnail
關於程式語言的學習,只要掌握住幾個基本特性要熟悉幾種程式語言也不困難,這三個基本特性就是…
Thumbnail
對許多駕駛而言,「路邊停車」絕對是最難克服的課題。而這次由比利時遊戲團隊Happy Volcano製作的小品遊戲《You Suck at Parking》,就是要讓玩家體驗到,路邊停車是有多麼困難的事情!
Thumbnail
而這次要介紹的這款遊戲《靈魂連結Soul Link》,是從俄羅斯方塊的機制衍生的造橋遊戲!?
Thumbnail
在近期,我在Steam發現了兩款挺不錯的自動攻擊Roguelite清版遊戲,其中一款是由Night Owls所製作的《Biters & Bullets》,另一款則是本篇文章要介紹的《靈魂石倖存者Soulstone Survivors》!
Thumbnail
在近期,我在Steam發現了兩款挺不錯的自動攻擊Roguelite清版遊戲,而其中一款,是由Night Owls所製作的《Biters & Bullets》,與其他類似遊戲不同的是,這是一款自動攻擊的Roguelite清版「射擊遊戲」!
Thumbnail
這個主題,主要是發表我對一款遊戲作品的前期試玩體驗的感想,裡面會有大量的個人主觀觀點,想跟你分享我試玩這款遊戲的心得。 本次試玩的作品為,由RAYKA STUDIO推出的遊戲作品《太古之火》。