您好,登錄后才能下訂單哦!
小編給大家分享一下Node.js如何實現多進程處理CPU密集任務,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
Node.js 單線程與多進程
大家都知道 Node.js 性能很高,是以異步事件驅動、非阻塞 I/O 而被廣泛使用。但缺點也很明顯,由于 Node.js 是單線程程序,如果長時間運算,會導致 CPU 不能及時釋放,所以并不適合 CPU 密集型應用。
當然,也不是沒有辦法解決這個問題。雖然 Node.js 不支持多線程,但是可創建多子進程來執行任務。
Node.js 提供了 child_process 和 cluster 兩個模塊可用于創建多子進程
下面我們就分別使用單線程和多進程來模擬查找大量斐波那契數進行 CPU 密集測試
以下代碼是查找 500 次位置為 35 的斐波那契數(方便測試,定了一個時間不需要太長也不會太短的位置)
單線程處理
代碼:single.js
function fibonacci(n) { if (n == 0 || n == 1) { return n; } else { return fibonacci(n - 1) + fibonacci(n - 2); } } let startTime = Date.now(); let totalCount = 500; let completedCount = 0; let n = 35; for (let i = 0; i < totalCount; i++) { fibonacci(n); completedCount++; console.log(`process: ${completedCount}/${totalCount}`); } console.log("? ? ? ? ? ? ? ? ? ?"); console.info(`任務完成,用時: ${Date.now() - startTime}ms`); console.log("? ? ? ? ? ? ? ? ? ?");
執行node single.js 查看結果
在我的電腦上顯示結果為44611ms(電腦配置不同也會有差異)。
...
process: 500/500
? ? ? ? ? ? ? ? ? ?
任務完成,用時: 44611ms
? ? ? ? ? ? ? ? ? ?
查找 500 次需要 44 秒,太慢了。可想而知如果位置更大,數量更多...
那我們來嘗試用多進程試試 ??
多進程
采用 cluster 模塊,Master-Worker 模式來測試
共 3 個 js,分別為主線程代碼:master.js、子進程代碼:worker.js、入口代碼:cluster.js(入口可無需單獨寫一個 js、這里是為了看起來更清楚一些)
主線程代碼:master.js
const cluster = require("cluster"); const numCPUs = require("os").cpus().length; // 設置子進程執行程序 cluster.setupMaster({ exec: "./worker.js", slient: true }); function run() { // 記錄開始時間 const startTime = Date.now(); // 總數 const totalCount = 500; // 當前已處理任務數 let completedCount = 0; // 任務生成器 const fbGenerator = FbGenerator(totalCount); if (cluster.isMaster) { cluster.on("fork", function(worker) { console.log(`[master] : fork worker ${worker.id}`); }); cluster.on("exit", function(worker, code, signal) { console.log(`[master] : worker ${worker.id} died`); }); for (let i = 0; i < numCPUs; i++) { const worker = cluster.fork(); // 接收子進程數據 worker.on("message", function(msg) { // 完成一個,記錄并打印進度 completedCount++; console.log(`process: ${completedCount}/${totalCount}`); nextTask(this); }); nextTask(worker); } } else { process.on("message", function(msg) { console.log(msg); }); } /** * 繼續下一個任務 * * @param {ChildProcess} worker 子進程對象,將在此進程上執行本次任務 */ function nextTask(worker) { // 獲取下一個參數 const data = fbGenerator.next(); // 判斷是否已經完成,如果完成則調用完成函數,結束程序 if (data.done) { done(); return; } // 否則繼續任務 // 向子進程發送數據 worker.send(data.value); } /** * 完成,當所有任務完成時調用該函數以結束程序 */ function done() { if (completedCount >= totalCount) { cluster.disconnect(); console.log("? ? ? ? ? ? ? ? ? ?"); console.info(`任務完成,用時: ${Date.now() - startTime}ms`); console.log("? ? ? ? ? ? ? ? ? ?"); } } } /** * 生成器 */ function* FbGenerator(count) { var n = 35; for (var i = 0; i < count; i++) { yield n; } return; } module.exports = { run };
1.這里是根據當前電腦的邏輯 CPU 核數來創建子進程的,不同電腦數量也會不一樣,我的 CPU 是 6 個物理核數,由于支持超線程處理,所以邏輯核數是 12,故會創建出 12 個子進程
2.主線程與子進程之間通信是通過send方法來發送數據,監聽message事件來接收數據
3.不知道大家有沒有注意到我這里使用了 ES6 的 Generator 生成器來模擬生成每次需要查找的斐波那契數位置(雖然是寫死的 ?,為了和上面的單線程保證統一)。這么做是為了不讓所有任務一次性扔出去,因為就算扔出去也會被阻塞,還不如放在程序端就給控制住,完成一個,放一個。
子進程代碼:worker.js
function fibonacci(n) { if (n == 0 || n == 1) { return n; } else { return fibonacci(n - 1) + fibonacci(n - 2); } } // 接收主線程發送過來的任務,并開始查找斐波那契數 process.on("message", n => { var res = fibonacci(n); // 查找結束后通知主線程,以便主線程再度進行任務分配 process.send(res); }); 入口代碼:cluster.js // 引入主線程js,并執行暴露出來的run方法 const master = require("./master"); master.run();
執行node cluster.js 查看結果
在我的電腦上顯示結果為10724ms(電腦配置不同也會有差異)。
process: 500/500
? ? ? ? ? ? ? ? ? ?
任務完成,用時: 10724ms
? ? ? ? ? ? ? ? ? ?
以上是“Node.js如何實現多進程處理CPU密集任務”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。