這篇文章帶給大家的內容是關於node.js中child_process模組和cluster模組的分析(程式碼範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
node遵循的是單執行緒單一進程的模式,node的單執行緒是指js的引擎只有一個實例,且在nodejs的主執行緒中執行,同時node以事件驅動的方式處理IO等非同步操作。 node的單線程模式,只維持一個主線程,大大減少了線程間切換的開銷。
但是node的單執行緒使得在主執行緒不能進行CPU密集型操作,否則會阻塞主執行緒。對於CPU密集型操作,在node中透過child_process可以建立獨立的子進程,父子進程透過IPC通信,子進程可以是外部應用程式也可以是node子程序,子進程執行後可以將結果傳回給父進程。
此外,node的單線程,以單一進程運行,因此無法利用多核心CPU以及其他資源,為了調度多核心CPU等資源,node還提供了cluster模組,利用多核心CPU的資源,使得可以通過一串node子程序去處理負載任務,同時確保一定的負載平衡型。本文從node的單線程單一進程的理解觸發,介紹了child_process模組和cluster模組
首先要理解的概念是,node的單執行緒和單一行程的模式。 node的單執行緒於其他語言的多執行緒模式相比,減少了執行緒間切換的開銷,以及在寫node程式碼的時候不用考慮鎖定以及執行緒池的問題。 node宣稱的單線程模式,比其他語言更適合IO密集型操作。那麼一個經典的問題是:
node是真的單執行緒的嗎?
提到node,我們就可以立刻想到單一執行緒、非同步IO、事件驅動等字眼。首先要明確的是node真的是單線程的嗎,如果是單線程的,那麼異步IO,以及定時事件(setTimeout、setInterval等)又是在哪裡被執行的。
嚴格來說,node並不是單線程的。 node中存在著多種線程,包括:
js引擎執行的線程
定時器線程(setTimeout, setInterval)
異步http線程(ajax)
#.
我們平時所說的單線程是指node中只有一個js引擎在主執行緒上運行。其他非同步IO和事件驅動相關的執行緒透過libuv來實現內部的執行緒池和執行緒調度。 libv中存在了一個Event Loop,透過Event Loop來切換實作類似多執行緒的效果。簡單的來講Event Loop就是維持一個執行棧和一個事件佇列,當前執行棧中的如果發現異步IO以及定時器等函數,就會把這些非同步回呼函數放入到事件佇列中。目前執行堆疊執行完成後,從事件佇列中,依照一定的順序執行事件佇列中的非同步回呼函數。
上圖中從執行棧,到事件佇列,最後事件佇列中依照一定的順序執行回呼函數,整個過程就是一個簡化版的Event Loop。另外回呼函數執行時,同樣會產生一個執行棧,在回呼函數裡面還有可能巢狀異步的函數,也就是說執行棧存在著巢狀。
也就是說node中的單執行緒是指js引擎只在唯一的主執行緒上運行,其他的非同步操作,也是有獨立的執行緒去執行,透過libv的Event Loop實現了類似於多線程的上下文切換以及線程池調度。執行緒是最小的進程,因此node也是單進程的。這樣就解釋了為什麼node是單執行緒和單一進程的。
node是單一進程的,必然存在一個問題,就是無法充分利用cpu等資源。 node提供了child_process模組來實現子進程,從而實現一個廣義上的多進程的模式。透過child_process模組,可以實現1個主進程,多個子進程的模式,主進程稱為master進程,子進程又稱為工作進程。在子進程中不僅可以呼叫其他node程序,也可以執行非node程序以及shell指令等等,執行完子程序後,以流或回調的形式回傳。
child_process提供了4個方法,用於新建子進程,這4個方法分別為spawn、execFile、exec和fork。所有的方法都是非同步的,可以用一張圖來描述這4個方法的差異。
上圖可以顯示出這4個方法的差別,我們也可以簡單介紹這4個方法的差異。
spawn : 子程序中執行的是非node程序,提供一組參數後,執行的結果以流的形式傳回。
execFile:子進程中執行的是非node程序,提供一組參數後,執行的結果以回呼的形式傳回。
exec:子進程執行的是非node程序,傳入一串shell命令,執行後結果以回調的形式返回,與execFile
不同的是exec可以直接執行一串shell指令。
fork:子進程執行的是node程序,提供一組參數後,執行的結果以流的形式返回,與spawn不同,fork生成的子進程只能執行node應用。接下來的小節將具體的介紹這一些方法。
我們先比較execFile和exec的差別,這兩個方法的相同點:
##執行的是非node應用,且執行後的結果以回呼函數的形式傳回。
不同點是:exec是直接執行的一段shell指令,而execFile是執行的一個應用程式
舉例來說,echo是UNIX系統的一個自帶命令,我們直接可以在命令列執行:echo hello world
(1) 透過exec來實作新建一個main.js檔案中,如果要使用exec方法,那麼則在該檔案中寫入:
let cp=require('child_process'); cp.exec('echo hello world',function(err,stdout){ console.log(stdout); });
let cp=require('child_process'); cp.execFile('echo',['hello','world'],function(err,stdout){ console.log(stdout); });
echo hello world;rm -rf
execFile('echo',['hello','world',';rm -rf'])
#在上述圖片示意圖中,首先讀取的input. txt檔案中有acba未經排序的文字,經過sort程式後可以實現排序功能,輸出為aabc,最後透過uniq程式可以去重,得到abc。我們可以用spawn流形式的輸入輸出來實現上述功能:
let cp=require('child_process'); let cat=cp.spawn('cat',['input.txt']); let sort=cp.spawn('sort'); let uniq=cp.spawn('uniq'); cat.stdout.pipe(sort.stdin); sort.stdout.pipe(uniq.stdin); uniq.stdout.pipe(process.stdout); console.log(process.stdout);
透過process.on('message')和process.send()的機制來接收和傳送訊息。
在父進程中:透過child.on('message')和process.send()的機制來接收和傳送消息。
具體例子,在child.js中:process.on('message',function(msg){ process.send(msg) })
let cp=require('child_process'); let child=cp.fork('./child'); child.on('message',function(msg){ console.log('got a message is',msg); }); child.send('hello world');
child.disconnect()
exec、execFile、spawn和fork执行的子进程都是默认异步的,子进程的运行不会阻塞主进程。除此之外,child_process模块同样也提供了execFileSync、spawnSync和execSync来实现同步的方式执行子进程。
cluster意为集成,集成了两个方面,第一个方面就是集成了child_process.fork方法创建node子进程的方式,第二个方面就是集成了根据多核CPU创建子进程后,自动控制负载均衡的方式。
我们从官网的例子来看:
const cluster = require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log(`主进程 ${process.pid} 正在运行`); // 衍生工作进程。 for (let i = 0; i { console.log(`工作进程 ${worker.process.pid} 已退出`); }); } else { // 工作进程可以共享任何 TCP 连接。 // 在本例子中,共享的是一个 HTTP 服务器。 http.createServer((req, res) => { res.writeHead(200); res.end('你好世界\n'); }).listen(8000); console.log(`工作进程 ${process.pid} 已启动`); }
最后输出的结果为:
$ node server.js 主进程 3596 正在运行 工作进程 4324 已启动 工作进程 4520 已启动 工作进程 6056 已启动 工作进程 5644 已启动
我们将master称为主进程,而worker进程称为工作进程,利用cluster模块,使用node封装好的API、IPC通道和调度机可以非常简单的创建包括一个master进程下HTTP代理服务器 + 多个worker进程多个HTTP应用服务器的架构。
本文首先介绍了node的单线程和单进程模式,接着从单线程的缺陷触发,介绍了node中如何实现子进程的方法,对比了child_process模块中几种不同的子进程生成方案,最后简单介绍了内置的可以实现子进程以及CPU进程负载均衡的内置集成模块cluster。
相关推荐:
Node.js中关于多进程模块Cluster的详细介绍以及如何使用
以上是node.js中child_process模組和cluster模組的分析(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!