求不更學不動之Node.js多執行緒
伴隨10.5.0的釋出,Node.js 新增了對多執行緒的實驗性支援(worker_threads模組)。
為什麼需要多執行緒?
Node.js由於JS的執行在單一執行緒,導致CPU密集計算的任務可能會使主執行緒會處於繁忙的狀態,進而影響服務的效能,雖然可以透過child_process模組建立子程式的方式來解決,但是一方面程式之間無法共享記憶體,另一方面建立程式的開銷也不小。所以在10.5.0版本中Node.js提供了worker_threads模組來支援多執行緒,一直以來被人所詬病的不擅長CPU密集計算有望成為歷史。
如何啟用多執行緒?
多執行緒目前仍然處於實驗階段,所以啟動時需要增加--experimental-worker
flag才能生效。
如何建立多執行緒?
worker_threads
模組中比較重要的幾個類:
MessageChannel: 用於建立非同步、雙向通訊的通道例項。MessageChannel例項包含兩個屬性port1和port2,這兩個屬性都是MessagePort的例項。
MessagePort: 用於表示MessageChannel通道的終端,用於Worker之間傳輸結構化資料、記憶體區域和其他的MessagePort。MessagePort繼承了EventEmitter,因此可以使用postMessage和on方法實現訊息的傳遞與接收。
Worker: 用於建立單獨的JS執行緒。
worker_threads
模組中比較重要的幾個屬性:
parentPort: 子執行緒中的parentPort指向可以與主執行緒進行通訊的MessagePort。
子執行緒向父執行緒傳送訊息
parentPort.postMessage(...)
子執行緒接受來自父執行緒的訊息
parentPort.on('message', (msg) => ...)
isMainThread: 用於區分當前檔案是否在主執行緒中執行
workerData: 用於傳遞給Worker建構函式的data副本,在子執行緒中可以透過workerData獲取到父程式傳入的資料。
瞭解常用類與屬性之後再來看一下程式碼示例
const { Worker, parentPort, isMainThread } = require('worker_threads'); if (isMainThread) { const w = new Worker(__filename, { workerData: { name: 'Randal' } }); w.postMessage(1e10); const startTime = Date.now(); w.on('message', function(msg) { console.log('main thread get message: ' + msg); console.log('compute time ellapsed: ' + (Date.now() - startTime) / 1000); }); console.log('main thread executing'); } else { const longComputation = (val) => { let sum = 0; for (let i = 0; i { console.log(`${workerData.name} worker get message: ` + msg); parentPort.postMessage(longComputation(msg)); }); } // 執行結果 main thread executing Randal worker get message: 10000000000 main thread get message: 49999999990067860000 compute time ellapsed: 14.954
執行緒間如何傳輸資料?
port.postMessag(value[, transferList])
除了value之外,postMessage方法還支援傳入transferList引數,transferList是一個List,支援的資料型別包括ArrayBuffer和MessagePort物件,transferList中的物件在傳輸完成後,在傳送物件的執行緒中就不可以繼續使用了。
const { Worker, isMainThread, parentPort } = require('worker_threads'); // 主執行緒 if (isMainThread) { const sab = new ArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 100); const ia = new Int32Array(sab); for (let i = 0; i { console.log('after transfer: ', sab); }, 1000); } } else { console.log("this isn't main thread"); } // 輸出結果 this is the main thread before transfer: ArrayBuffer { byteLength: 400 } this isn't main thread after transfer: ArrayBuffer { byteLength: 0 }
如果ArrayBuffer是透過value傳輸的(且在transferList中不存在),則傳輸過去的是副本,如下所示:
w.postMessage(sab); // 輸出結果 this is the main thread before transfer: ArrayBuffer { byteLength: 400 } this isn't main thread after transfer: ArrayBuffer { byteLength: 400 }
執行緒間如何共享記憶體?
輪到SharedArrayBuffer出場了,如果postMessage中的value是SharedArrayBuffer的話,則執行緒之間就可以共享記憶體,如下面例子所示:
const { Worker, isMainThread, parentPort } = require('worker_threads'); // 主執行緒 if (isMainThread) { const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 5); const ia = new Int32Array(sab); for (let i = 0; i { console.log(ia); }); } } else { parentPort.on('message', (msg) => { const ia = new Int32Array(msg, 0, 1); ia[0] = ia[0] + 1; parentPort.postMessage('done'); }); } // 輸出結果 Int32Array [ 1, 1, 2, 3, 4 ] Int32Array [ 2, 1, 2, 3, 4 ]
參考資料
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4289/viewspace-2803274/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 求不更學不動之Redis5.0新特性Stream嚐鮮Redis
- 看完這篇多執行緒,再說多執行緒學不會,那你就收藏多看兩遍執行緒
- 嗯!這篇多執行緒不錯!伍執行緒
- 多執行緒系列之 執行緒安全執行緒
- iOS 多執行緒之執行緒安全iOS執行緒
- Java多執行緒之執行緒中止Java執行緒
- Android多執行緒之執行緒池Android執行緒
- Node.js 多執行緒完全指南Node.js執行緒
- 多執行緒學習一(多執行緒基礎)執行緒
- 多執行緒之NSOperation執行緒
- java多執行緒之執行緒的基本使用Java執行緒
- Node.js 真·多執行緒 Worker Threads 初探Node.js執行緒thread
- Java多執行緒學習——執行緒通訊Java執行緒
- Java多執行緒學習(2)執行緒控制Java執行緒
- 最全java多執行緒總結3——瞭解阻塞佇列和執行緒安全集合不Java執行緒佇列
- #大學#Java多執行緒學習02(執行緒同步)Java執行緒
- Java多執行緒之守護執行緒實戰Java執行緒
- 併發與多執行緒之執行緒安全篇執行緒
- 多執行緒之間通訊及執行緒池執行緒
- Java多執行緒之執行緒同步【synchronized、Lock、volatitle】Java執行緒synchronized
- Java多執行緒學習(一)Java多執行緒入門Java執行緒
- iOS 多執行緒之GCDiOS執行緒GC
- iOS 多執行緒之NSOperationiOS執行緒
- iOS 多執行緒之NSThreadiOS執行緒thread
- iOS 多執行緒之NSOperationQueueiOS執行緒
- Java多執行緒之FutureTaskJava執行緒
- 多執行緒之共享模型執行緒模型
- Java多執行緒之CASJava執行緒
- java多執行緒之(synchronized)Java執行緒synchronized
- IOS多執行緒之(GCD)iOS執行緒GC
- 多執行緒和多執行緒同步執行緒
- performSelector:withObject:afterDelay: 在子執行緒中呼叫不執行performSelectorObject執行緒
- Java多執行緒學習(3)執行緒同步與執行緒通訊Java執行緒
- iOS 多執行緒-學習iOS執行緒
- Java多執行緒學習Java執行緒
- 多執行緒學習(二)執行緒
- 多執行緒學習一執行緒
- 多執行緒--執行緒管理執行緒