nodejs-child_process

child_process

node遵循的是單線程單進程的模式,node的單線程是指js的引擎只有一個實例,且在nodejs的主線程中執行,同時node以事件驅動的方式處理IO等異步操作。node的單線程模式,只維持一個主線程,大大減少了線程間切換的開銷。

但是node的單線程使得在主線程不能進行CPU密集型操作,否則會阻塞主線程。對於CPU密集型操作,在node中通過child_process可以創建獨立的子進程,父子進程通過IPC通信,子進程可以是外部應用也可以是node子程序,子進程執行後可以將結果返回給父進程。

我們平時所說的單線程是指node中只有一個js引擎在主線程上運行。其他異步IO和事件驅動相關的線程通過libuv來實現內部的線程池和線程調度。libv中存在了一個Event Loop,通過Event Loop來切換實現類似於多線程的效果。簡單的來講Event Loop就是維持一個執行棧和一個事件隊列,當前執行棧中的如果發現異步IO以及定時器等函數,就會把這些異步回調函數放入到事件隊列中。當前執行棧執行完成後,從事件隊列中,按照一定的順序執行事件隊列中的異步回調函數。


創建子進程

child_process提供了4個方法,用於新建子進程,這4個方法分別爲spawn、execFile、exec和fork,所有的方法都是異步。

  • spawn : 子進程中執行的是非node程序,提供一組參數後,執行的結果以流的形式返回。
  • execFile:子進程中執行的是非node程序,提供一組參數後,執行的結果以回調的形式返回。
  • exec:子進程執行的是非node程序,傳入一串shell命令,執行後結果以回調的形式返回,與execFile
    不同的是exec可以直接執行一串shell命令。
  • fork:子進程執行的是node程序,提供一組參數後,執行的結果以流的形式返回,與spawn不同,fork生成的子進程只能執行node應用。接下來的小節將具體的介紹這一些方法。

注意:非node程序,所以要執行的話,要用shell執行,比如 執行 t.js ,則在shell上,用 node ./t.js執行,後面跟js文件的路徑。


spawn

示例:

const childProcess = require("child_process");

const hello = childProcess.spawn("echo",['hello','world']);
hello.stdout.pipe(process.stdout);

運行shell命令echo(打印),參數用數組包含,不直接執行 echo hello world,是爲了防止注入攻擊,將流導入控制檯的輸出。然後控制檯會打印 hello world.


exec

示例:

const childProcess = require("child_process");

childProcess.exec("echo hello world",(error,stdout)=>{
    if (error) {
        console.log(error);
    }else {
        console.log(stdout);
    }
});

exec,就可以直接運行shell命令,但是這樣比較危險。如果在後面又加了一條rm指令,就有意思了。所有爲了讓程序按照我們預期的運行,建議不用exec,可以用execFile代替。

所以有了execFile,它可以防止注入攻擊。


execFile

const childProcess = require("child_process");

childProcess.execFile('echo',['hello','world'],(error,stdout)=>{
    if (error) {
        console.log(error);
    }else {
        console.log(stdout);
    }
});

與exec相比,參數是以數組的方式傳入。


fork

前面的都是運行 shell 程序,fork可以運行node子進程,並且可以與父進程進行通信。

示例:

fork-child.js:

console.log(`I am child`);
process.send("hello parent");
process.on(`message`,message=>{
    console.log(`child receive: ${message}`);
});

parent:

const childProcess = require("child_process");

console.log(`I am parent`);
const spawn = childProcess.fork("./fork-child");
spawn.on('message',message=>{
    console.log(`parent receive: ${message}`);
    spawn.send("hello child");
});

運行parent:

I am parent
I am child
parent receive: hello parent
child receive: hello child

上面程序是,先是fork了一個子進程,子進程就運行了,然後子進程向父進程發送消息,parent監聽到了並打印,並向child發送了一條消息,child也監聽到了並打印了父進程發送的消息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章