nodejs怎么處理密集型計算的?相信有很多人都不太了解,今天小編為了讓大家更加了解nodejs,所以給大家總結(jié)了以下內(nèi)容,一起往下看吧。
專注于為中小企業(yè)提供成都網(wǎng)站建設(shè)、做網(wǎng)站服務(wù),電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)讓胡路免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了超過千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
nodejs 如何處理密集型計算?
Nodejs密集型CPU解決方案
首先說一下nodejs單線程的優(yōu)勢:
高性能,與php相比,避免了頻繁創(chuàng)建切換線程的開銷,執(zhí)行更加迅速,資源占用小。
線程安全,不用擔(dān)心同一變量被多線程讀寫,造成程序崩潰。
單線程的異步和非阻塞,其實 nodejs底層訪問I/O還是多線程的,阻塞/非阻塞與異步/同步是兩個不同的概念,同步不代表阻塞,但是阻塞肯定就是同步;有點兒繞口,請聽我舉例,我去食堂打飯,我選擇了A套餐,然后工作人員幫我去配餐,如果我就站在旁邊,等待工作人員給我配餐,這種情況就稱之為同步;若工作人員幫我配餐的同時,排在我后面的人就開始點餐,這樣整個食堂的點餐服務(wù)并沒有因為我在等待A套餐而停止,這種情況就稱之為非阻塞。這個例子就簡單說明了同步但非阻塞的情況。再如果我在等待配餐的時候去買飲料,等聽到叫號再回去拿套餐,此時我的飲料也已經(jīng)買好,這樣我在等待配餐的同時還執(zhí)行了買飲料的任務(wù),叫號就等于執(zhí)行了回調(diào),就是異步非阻塞了。如果我在買飲料的時候,已經(jīng)叫我的號讓我去拿套餐,可是我等了好久才拿到飲料,所以我可能在大廳叫我的餐號之后很久才拿到A套餐,這也就是單線程的阻塞情況。
多線程:
線程是cpu調(diào)度的一個基本單位,一個cpu只能執(zhí)行一個線程任務(wù)。
nodejs也可以執(zhí)行多行程任務(wù),例如引用TAGG/TAGG2模塊,但是不論是tagg/tagg2都是利用pthread庫和V8::Isolate類來實現(xiàn)js多線程功能的,根據(jù)規(guī)則我們在線程里執(zhí)行的函數(shù)無法使用nodejs的核心api,例如fs,crypto模塊,所以還是有很大的局限性。
多進(jìn)程:
在支持html5的瀏覽器里,我們可以使用webworker來將一些耗時的計算丟入worker進(jìn)程中執(zhí)行,這樣主進(jìn)程就不會阻塞,用戶也不會有卡頓的感覺。
這里我們需要利用nodejs的child_process模塊,child_process提供了fork方法,可以啟動一個nodejs文件,將它視作worker進(jìn)程,worker 工作完畢后,會把結(jié)果send給主進(jìn)程,然后worker自動退出,這樣我們就利用了多進(jìn)程解決了主線程阻塞的問題。
var express = require('express'); var fork = require('child_process').fork; var app = express(); app.get('/', function(req, res){ var worker = fork('./work.js') //創(chuàng)建一個工作進(jìn)程 worker.on('message', function(m) {//接收工作進(jìn)程計算結(jié)果 if('object' === typeof m && m.type === 'fibo'){ worker.kill();//發(fā)送殺死進(jìn)程的信號 res.send(m.result.toString());//將結(jié)果返回客戶端 } }); worker.send({type:'fibo',num:~~req.query.n || 1}); //發(fā)送給工作進(jìn)程計算fibo的數(shù)量 }); app.listen(7878);
我們通過express監(jiān)聽7878端口,對每個用戶的請求都會去fork一個子進(jìn)程,通過調(diào)用worker.send方法將參數(shù)n傳遞給子進(jìn)程,同時監(jiān)聽子進(jìn)程發(fā)送消息的message事件,將結(jié)果響應(yīng)給客戶端。
下面是被fork的work.js文件內(nèi)容:
var fibo = function fibo (n) {//定義算法 return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1; } process.on('message', function(m) { //接收主進(jìn)程發(fā)送過來的消息 if(typeof m === 'object' && m.type === 'fibo'){ var num = fibo(~~m.num); //計算jibo process.send({type: 'fibo',result:num}) //計算完畢返回結(jié)果 } }); process.on('SIGHUP', function() { process.exit();//收到kill信息,進(jìn)程退出 });
我們先定義函數(shù)fibo用來計算斐波那契數(shù)組,然后監(jiān)聽了主線程發(fā)來的消息,計算完畢之后將結(jié)果send到主線程。同時還監(jiān)聽process的SIGHUP事件,觸發(fā)此事件就進(jìn)程退出。
這里我們有一點需要注意,主線程的kill方法并不是真的使子進(jìn)程退出,而是會觸發(fā)子進(jìn)程的SIGHUP事件,真正的退出還是依靠process.exit()。
總結(jié):
使用child_process模塊的fork方法確實可以讓我們很好的解決單線程對cpu密集型任務(wù)的阻塞問題,同時又沒有tagg包那樣無法使用Node.js核心api的限制。
單線程異步的Node.js不代表不會阻塞,在主線程做過多的任務(wù)可能會導(dǎo)致主線程的卡死,影響整個程序的性能,所以我們要非常小心的處理大量的循環(huán),字符串拼接和浮點運算等cpu密集型任務(wù),合理的利用各種技術(shù)把任務(wù)丟給子線程或子進(jìn)程去完成,保持Node.js主線程的暢通。
線程/進(jìn)程的使用并不是沒有開銷的,盡可能減少創(chuàng)建和銷毀線程/進(jìn)程的次數(shù),可以提升我們系統(tǒng)整體的性能和出錯的概率。
以上就是nodejs怎么處理密集型計算的的詳細(xì)內(nèi)容了,看完之后是否有所收獲呢?如果想了解更多相關(guān)內(nèi)容,歡迎來創(chuàng)新互聯(lián)行業(yè)資訊!
名稱欄目:nodejs怎么處理密集型計算的
網(wǎng)站鏈接:http://m.newbst.com/article36/gpjesg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、網(wǎng)站維護(hù)、網(wǎng)站導(dǎo)航、網(wǎng)站建設(shè)、域名注冊、軟件開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)