【程式語言 - 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
為什麼會看到廣告
avatar-img
118會員
264內容數
哈囉,我是阿Han,是一位 👩‍💻 軟體研發工程師,喜歡閱讀、學習、撰寫文章及教學,擅長以圖代文,化繁為簡,除了幫助自己釐清思路之外,也希望藉由圖解的方式幫助大家共同學習,甚至手把手帶您設計出高品質的軟體產品。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
阿Han的沙龍 的其他內容
概念: 有限時間內可使用通行證來要求對應的操作權限。 JWT 的組成內容有三個部分,由 . 做區隔,最後透過這三個部分,串成一個 Jwt 字串 [HEADER].[PAYLOAD].[SIGNATURE] 1. Header: 主要記載認證的方法 {     "typ": "JWT",     "
概念: 有限時間內可使用通行證來要求對應的操作權限。 JWT 的組成內容有三個部分,由 . 做區隔,最後透過這三個部分,串成一個 Jwt 字串 [HEADER].[PAYLOAD].[SIGNATURE] 1. Header: 主要記載認證的方法 {     "typ": "JWT",     "
你可能也想看
Google News 追蹤
Thumbnail
Node.js是一個JavaScript運行環境。它使用了一個非阻塞、事件驅動的I/O模型,使其非常適合用於數據密集型的即時應用程序。簡單來說,Node.js允許你使用JavaScript來編寫伺服器端代碼。 nvm 安裝nvm Windows : 點擊 Releases · coreybut
Thumbnail
簡要說明 JavaScript 的 Event Loop JavaScript 是單執行緒 (single-threaded) 語言,這意味著它一次只能執行一件事,因此所有函式都需要排隊等待執行,這被稱為同步 (synchronous)。在同步操作中,若函式過多或過於複雜,會導致程式阻塞 (blo
※ 何謂巢狀迴圈(NESTD LOOP): 指的是一個迴圈內包含另一個迴圈的結構。在程式設計中,這種結構常用於需要進行多層次迭代的場合,例如處理多維數組、逐行逐列處理表格資料等。 ※ 例子:九九乘法表 說明: 外層迴圈:for (let i = 1; i <= 9; i = i + 1) 這
Thumbnail
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
Thumbnail
npm(全名 Node Package Manager,node套件管理器)
Thumbnail
當你需要在 Python 中執行多個任務,但又不希望它們相互阻塞時,可以使用 threading 模組。 threading 模組允許你在單個程序中創建多個執行緒,這些執行緒可以同時運行,從而實現並行執行多個任務的效果。
Thumbnail
題目敘述 題目會給定一個下標從 0 開始的整數陣列 costs , 其中 costs[i] 是雇傭第 i 位員工的代價。 同時給你兩個整數 k 和 candidates 。我們想根據以下規則恰好雇傭 k 位員工: 總共進行 k 輪雇傭,且每一輪恰好雇傭一位員工。 在每一輪雇傭中,從最前面
Thumbnail
Service Worker 是用於客戶端的攔截器,可以使用 Cache Storage 和 IndexDB,並有自己的生命週期。Web Worker 用於處理可能會使用到大量運算且不希望影響到使用者體驗的任務。Shared Worker 可以在相同 Domain 的不同頁面上共享訊息。
Thumbnail
非同步程式設計(Asynchronous programming) 或是簡單的稱之為 async,它是一種並發程式模型(concurrent programming model),其目的就是讓多個任務能同時在作業系統的執行緒上執行,並透過 async/.await 保留同步。
Thumbnail
Node.js是一個JavaScript運行環境。它使用了一個非阻塞、事件驅動的I/O模型,使其非常適合用於數據密集型的即時應用程序。簡單來說,Node.js允許你使用JavaScript來編寫伺服器端代碼。 nvm 安裝nvm Windows : 點擊 Releases · coreybut
Thumbnail
簡要說明 JavaScript 的 Event Loop JavaScript 是單執行緒 (single-threaded) 語言,這意味著它一次只能執行一件事,因此所有函式都需要排隊等待執行,這被稱為同步 (synchronous)。在同步操作中,若函式過多或過於複雜,會導致程式阻塞 (blo
※ 何謂巢狀迴圈(NESTD LOOP): 指的是一個迴圈內包含另一個迴圈的結構。在程式設計中,這種結構常用於需要進行多層次迭代的場合,例如處理多維數組、逐行逐列處理表格資料等。 ※ 例子:九九乘法表 說明: 外層迴圈:for (let i = 1; i <= 9; i = i + 1) 這
Thumbnail
分享在網路上看到的陣列題目。通常 for...of 的 value 是陣列中的每個值,那如果我們在迭代中對陣列操作會發生什麼事? 題目來源:https://x.com/_jayphelps/status/1774640511158022335?s=20
Thumbnail
npm(全名 Node Package Manager,node套件管理器)
Thumbnail
當你需要在 Python 中執行多個任務,但又不希望它們相互阻塞時,可以使用 threading 模組。 threading 模組允許你在單個程序中創建多個執行緒,這些執行緒可以同時運行,從而實現並行執行多個任務的效果。
Thumbnail
題目敘述 題目會給定一個下標從 0 開始的整數陣列 costs , 其中 costs[i] 是雇傭第 i 位員工的代價。 同時給你兩個整數 k 和 candidates 。我們想根據以下規則恰好雇傭 k 位員工: 總共進行 k 輪雇傭,且每一輪恰好雇傭一位員工。 在每一輪雇傭中,從最前面
Thumbnail
Service Worker 是用於客戶端的攔截器,可以使用 Cache Storage 和 IndexDB,並有自己的生命週期。Web Worker 用於處理可能會使用到大量運算且不希望影響到使用者體驗的任務。Shared Worker 可以在相同 Domain 的不同頁面上共享訊息。
Thumbnail
非同步程式設計(Asynchronous programming) 或是簡單的稱之為 async,它是一種並發程式模型(concurrent programming model),其目的就是讓多個任務能同時在作業系統的執行緒上執行,並透過 async/.await 保留同步。