在中,javascript程式碼的執行是單執行緒執行的,可是Node 本身其實是多執行緒的。
node本身分為三層
第一層,Node.js 標準庫,這部分是由 Javascript編寫的,即我們使用過程中直接能呼叫的 API,在原始碼中的 lib 目錄下可以看到。
第二層,Node bindings,這一層是 Javascript 與底層 C/C++ 能夠溝通的關鍵,前者通過 bindings 呼叫後者,相互交換資料,是第一層和第三層的橋樑。
第三層,是支撐 Node.js 執行的關鍵,由 C/C++ 實現,是node實現的一些底層邏輯。
其中,第三層的Libuv,為 Node.js 提供了跨平臺,執行緒池,事件池,非同步 I/O 等能力,是 Node.js 如此強大的關鍵。
由於Libuv提供了事件迴圈機制,所以在io處理方面,javascript並不會發生阻塞,所以我們用node搭建web服務時,並不需要擔心io量過大,導致其他請求阻塞。
可是,非io任務的執行,是在node主執行緒中執行的,是單執行緒執行任務,如果有非常消耗時間的同步計算任務,將會阻塞其他程式碼的執行。
const Koa = require('koa'); const app = new Koa(); app.use(async (ctx) => { const url = ctx.request.url; if (url === '/') { ctx.body = {name: 'xxx', age: 14} } if(url==='/compute'){ let sum=0 for (let i = 0; i <100000000000 ; i++) { sum+=i } ctx.body={sum} } }) app.listen(4000, () => { console.log('http://localhost:4000/ start') })
上面這串程式碼,如果http請求了 /compute
,node會呼叫cpu進行大量的計算,這時如果有其他http請求進入,將會發生阻塞。
那麼如何解決這個問題呢?
有兩種方案,一種是使用children_process
或者cluster
開啟多程序進行計算,一種是使用worker_thread
開啟多執行緒進行計算
多程序 vs 多執行緒
對比一下多執行緒與多程序:
屬性 | 多程序 | 多執行緒 | 比較 |
---|---|---|---|
資料 | 資料共用複雜,需要用IPC;資料是分開的,同步簡單 | 因為共用程序資料,資料共用簡單,同步複雜 | 各有千秋 |
CPU、記憶體 | 佔用記憶體多,切換複雜,CPU利用率低 | 佔用記憶體少,切換簡單,CPU利用率高 | 多執行緒更好 |
銷燬、切換 | 建立銷燬、切換複雜,速度慢 | 建立銷燬、切換簡單,速度很快 | 多執行緒更好 |
coding | 編碼簡單、偵錯方便 | 編碼、偵錯複雜 | 編碼、偵錯複雜 |
可靠性 | 程序獨立執行,不會相互影響 | 執行緒同呼吸共命運 | 多程序更好 |
分散式 | 可用於多機多核分散式,易於擴充套件 | 只能用於多核分散式 | 多程序更好 |
採用多執行緒來解決上面程式碼的計算問題:
//api.js const Koa = require('koa'); const app = new Koa(); const {Worker} = require('worker_threads') app.use(async (ctx) => { const url = ctx.request.url; if (url === '/') { ctx.body = {name: 'xxx', age: 14} } if (url === '/compute') { const sum = await new Promise(resolve => { const worker = new Worker(__dirname+'/compute.js') //接收資訊 worker.on('message', data => { resolve(data) }) }) ctx.body = {sum} } }) app.listen(4000, () => { console.log('http://localhost:4000/ start') }) //computer.js const {parentPort}=require('worker_threads') let sum=0 for (let i = 0; i <1000000000 ; i++) { sum+=i } //傳送資訊 parentPort.postMessage(sum)
這裡是官方檔案,worker_threads
https://nodejs.org/dist/latest-v16.x/docs/api/worker_threads.html
採用多程序來解決上面程式碼的計算問題:
//api.js const Koa = require('koa'); const app = new Koa(); const {fork} = require('child_process') app.use(async (ctx) => { const url = ctx.request.url; if (url === '/') { ctx.body = {name: 'xxx', age: 14} } if (url === '/compute') { const sum = await new Promise(resolve => { const worker =fork(__dirname+'/compute.js') worker.on('message', data => { resolve(data) }) }) ctx.body = {sum} } }) app.listen(4000, () => { console.log('http://localhost:4000/ start') }) //computer.js let sum=0 for (let i = 0; i <1000000000 ; i++) { sum+=i } process.send(sum)
這裡是官方檔案,child_process
https://nodejs.org/dist/latest-v16.x/docs/api/child_process.html
更多node相關知識,請存取:!
以上就是一文聊聊node的多程序和多執行緒的詳細內容,更多請關注TW511.COM其它相關文章!