Nodejs-child_process模塊詳細(xì)介紹
在 Node.js 應(yīng)用程序中,child 進(jìn)程模塊非常重要,有了它可以實(shí)現(xiàn)并行處理,這在資源密集型任務(wù)里十分重要。
在本文中,我們將看一下 child 進(jìn)程模塊,解釋其目的、使用方式以及如何使用。
什么是子進(jìn)程模塊
子進(jìn)程是核心模塊,允許用戶創(chuàng)建和控制子進(jìn)程。這些進(jìn)程可以執(zhí)行系統(tǒng)命令、運(yùn)行各種語(yǔ)言的腳本,甚至可以創(chuàng)建新的 Node.js 實(shí)例。
child 進(jìn)程模塊的主要目的是允許同時(shí)執(zhí)行多個(gè)進(jìn)程,而不會(huì)阻塞主事件循環(huán)。
對(duì)于需要處理 CPU 密集型操作或執(zhí)行外部命令和腳本的應(yīng)用來(lái)說(shuō),使用 child 進(jìn)程可以確保應(yīng)用的高性能和響應(yīng)性。
子進(jìn)程的使用方式
child 進(jìn)程可以用于以下任務(wù):
并行處理:
Child處理通過(guò)允許應(yīng)用程序?qū)⒐ぷ髫?fù)載分布在多個(gè) CPU 核心上,從而顯著提高 CPU 密集型活動(dòng)(如圖像處理和數(shù)據(jù)分析)的性能。運(yùn)行 shell 腳本:
Child進(jìn)程可以用來(lái)執(zhí)行 shell 腳本。您可以使用exec技術(shù)來(lái)運(yùn)行 shell 命令并捕獲它們的輸出,還可以使用spawn方法,當(dāng)直接運(yùn)行腳本時(shí)提供更大的控制。與其他服務(wù)通信:在通信方面,
child進(jìn)程起著至關(guān)重要的作用。它可以與外部服務(wù)(如數(shù)據(jù)庫(kù)、API 或微服務(wù))進(jìn)行通信。它們可以用來(lái)調(diào)用外部 API,執(zhí)行數(shù)據(jù)庫(kù)查詢,與其它微服務(wù)通信。
創(chuàng)建子進(jìn)程
要?jiǎng)?chuàng)建一個(gè) child 進(jìn)程,Node.js 為我們提供了四種主要方法來(lái)創(chuàng)建一個(gè) child 進(jìn)程,分別是 exec(), execFile(), spawn(), fork()
exec() 方法
exec() 方法在 shell 中運(yùn)行一個(gè)命令并緩沖輸出。它適用于運(yùn)行 shell 命令并記錄輸出。但由于是緩沖,它有內(nèi)存限制。
下面是一個(gè)使用 exec() 方法執(zhí)行命令并獲取和處理一些系統(tǒng)信息的例子。
const { exec } = require("child_process");
exec("df -h", (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error.message}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
const lines = stdout.trim().split("\n");
const diskInfo = lines[1].split(/\s+/);
const totalSpace = diskInfo[1];
const usedSpace = diskInfo[2];
const availableSpace = diskInfo[3];
const usagePercent = diskInfo[4];
console.log(`Total Space: ${totalSpace}`);
console.log(`Used Space: ${usedSpace}`);
console.log(`Available Space: ${availableSpace}`);
console.log(`Usage: ${usagePercent}`);
});這將執(zhí)行 df -h 命令,解析其輸出,并顯示總的、已用的和可用的磁盤(pán)空間以及使用百分比。
運(yùn)行代碼時(shí),您應(yīng)該會(huì)看到類(lèi)似這樣的內(nèi)容:

execFile() 方法
execFile() 方法在沒(méi)有 shell 的情況下運(yùn)行可執(zhí)行文件。它比 exec() 更高效,因?yàn)樗苊饬?shell 的開(kāi)銷(xiāo)。
下面是一個(gè)如何使用 execFile() 方法的例子:
const { execFile } = require('child_process');
execFile("node", ["--version"], (error, stdout, stderr) => {
if (error) {
console.error(`execFile error: ${error.message}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});這個(gè)例子展示了運(yùn)行 Node.js 可執(zhí)行文件來(lái)獲取其版本。當(dāng)命令不需要 shell 特性時(shí),推薦使用 execFile()。
spawn() 方法
與主要用于執(zhí)行 shell 命令或可執(zhí)行文件并捕獲其輸出的 exec 方法不同,spawn() 方法通過(guò)基于流的輸出處理、直接與可執(zhí)行文件交互、事件驅(qū)動(dòng)的通信,提供了對(duì) child 進(jìn)程的更多控制。
spawn() 方法可用于需要直接交互的復(fù)雜場(chǎng)景。spawn() 啟動(dòng)一個(gè)新進(jìn)程,給定一個(gè)命令,并提供流 i.e stdout, stderr 用于直接處理進(jìn)程的輸出和錯(cuò)誤。
下面是一個(gè)如何使用 spawn() 方法的例子
const { spawn } = require("child_process");
const ls = spawn("ls", ["-lh", "/usr"]);
ls.stdout.on("data", (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on("data", (data) => {
console.error(`stderr: ${data}`);
});
ls.on("close", (code) => {
console.log(`child process exited with code $[code]`);
});在這個(gè)例子中,spawn() 運(yùn)行 ls 命令并附加事件偵聽(tīng)器來(lái)處理進(jìn)程的輸出和退出狀態(tài)。
運(yùn)行代碼時(shí),您應(yīng)該會(huì)看到類(lèi)似這樣的內(nèi)容:

fork() 方法
fork() 方法可以說(shuō)是為創(chuàng)建新的 Node.js 進(jìn)程而設(shè)計(jì)的 spawn() 的變體。與可以啟動(dòng)任何類(lèi)型進(jìn)程的 spawn() 不同,fork() 方法針對(duì)創(chuàng)建本身是 Node.js 應(yīng)用程序的 child 進(jìn)程進(jìn)行了優(yōu)化。
它為 child 進(jìn)程提供了一個(gè)額外的通信通道,允許在父進(jìn)程和 child 進(jìn)程之間進(jìn)行簡(jiǎn)單的消息傳輸。
下面是一個(gè)如何使用 fork() 方法的例子。
父文件,即 parent.js:
const { fork } = require("child_process");
const child = fork("child.js");
child.on("message", (message) => {
console.log(`Message from child: ${message}`);
});
child.send("Hello, child process!");child 進(jìn)程文件,即 child.js:
process.on("message", (message) => {
console.log(`Message from parent: ${message}`);
process.send("Hello from child process!");
});在這里,fork() 創(chuàng)建了一個(gè)運(yùn)行 child.js 腳本的新 Node.js 進(jìn)程。它允許使用 send() 和 message 事件在父進(jìn)程和子進(jìn)程之間傳遞消息。
當(dāng)您運(yùn)行代碼時(shí),您應(yīng)該會(huì)看到類(lèi)似這樣的內(nèi)容:

fork() 與 spawn() 之間的區(qū)別
fork 和 spawn 之間的一些區(qū)別包括:
內(nèi)置通信通道:
fork()在父進(jìn)程和child進(jìn)程之間自動(dòng)設(shè)置了一個(gè) IPC(進(jìn)程間通信)通道。相比之下,spawn()默認(rèn)不建立這個(gè)通道;如果需要,開(kāi)發(fā)人員必須手動(dòng)配置 IPC。隔離和獨(dú)立性:每個(gè)由
fork()生成的child進(jìn)程都是一個(gè)單獨(dú)的 Node.js 進(jìn)程,擁有自己的 V8 實(shí)例。另一方面,spawn()方法可以啟動(dòng)任何進(jìn)程,包括 Node.js 應(yīng)用程序,并不提供相同級(jí)別的隔離。用例特異性:
fork()技術(shù)專(zhuān)門(mén)用于需要生成工作進(jìn)程的情況,這些工作進(jìn)程是同一應(yīng)用程序的一部分,但同時(shí)運(yùn)行。相比之下,spawn()更為通用,用于需要啟動(dòng) Node.js 生態(tài)系統(tǒng)之外的任意命令或腳本時(shí)。
處理子進(jìn)程輸出
當(dāng)創(chuàng)建一個(gè) child 進(jìn)程時(shí),它會(huì)在兩個(gè)主要流中產(chǎn)生輸出:stdout 和 stderr。這些流保存了由 child 進(jìn)程運(yùn)行的命令或腳本的結(jié)果。要收集此輸出,請(qǐng)為 child 進(jìn)程對(duì)象添加事件偵聽(tīng)器,以在 stdout 和 stderr 上的 data 事件上。
Node.js 提供了幾種特別有用的事件偵聽(tīng)器,用于處理 child 進(jìn)程輸出和錯(cuò)誤。其中包括:
Data:數(shù)據(jù)事件由代表子進(jìn)程的 stdout 和 stderr 的流發(fā)出。Error:
當(dāng)child進(jìn)程執(zhí)行過(guò)程中發(fā)生錯(cuò)誤時(shí),會(huì)觸發(fā)錯(cuò)誤事件。這可能是由于命令本身的問(wèn)題,或者是讀取stdout或stderr時(shí)出現(xiàn)問(wèn)題。Close:當(dāng)child進(jìn)程結(jié)束時(shí),會(huì)發(fā)出關(guān)閉事件,表明它是否成功終止或被殺死。
讓我們看一個(gè)示例,展示如何生成一個(gè) child 進(jìn)程,捕獲其輸出,并處理可能發(fā)生的任何錯(cuò)誤。
我們將使用 spawn() 方法來(lái)啟動(dòng)一個(gè)簡(jiǎn)單的命令(echo)并偵聽(tīng)輸出和錯(cuò)誤。
const { spawn } = require("child_process");
const child = spawn("echo", ["Hello, world"]);
child.stdout.on("data", (data) => {
console.log(`stdout: ${data}`);
});
child.stderr.on("data", (data) => {
console.error(`stderr: ${data}`);
});
child.on("error", (error) => {
console.error(`Error occurred: ${error.message}`);
});
child.on("close", (code) => {
console.log(`Child process exited with code $[code]`);
});在這個(gè)例子中,父進(jìn)程生成一個(gè) child 進(jìn)程來(lái)執(zhí)行 echo 命令,該命令簡(jiǎn)單地將 Hello, world! 打印到終端。
父進(jìn)程通過(guò)附加到 stdout 和 stderr 的 data 事件偵聽(tīng)器來(lái)捕獲此輸出。此外,它還偵聽(tīng) error 事件以捕獲在執(zhí)行 child 進(jìn)程期間可能發(fā)生的任何錯(cuò)誤。
最后,close 事件指示 child 進(jìn)程已完成執(zhí)行,以及退出代碼,這可以用來(lái)確定進(jìn)程是否成功完成。
進(jìn)程間通信
在分布式系統(tǒng)和并發(fā)編程中,進(jìn)程間通信對(duì)于組件協(xié)調(diào)至關(guān)重要。Node.js 通過(guò)其 child 進(jìn)程模塊改進(jìn)了這種通信。這使您能夠創(chuàng)建 child 進(jìn)程并促進(jìn)進(jìn)程間通信(IPC)。
這種 IPC 機(jī)制,特點(diǎn)是父進(jìn)程和 child 進(jìn)程之間交換數(shù)據(jù),對(duì)于構(gòu)建模塊化和可擴(kuò)展的應(yīng)用程序至關(guān)重要。
有幾種方法可以促進(jìn);一個(gè)突出的方法是通過(guò) send() 方法和 message 事件進(jìn)行消息傳遞。這種方法利用了 child 進(jìn)程對(duì)象上可用的 send() 函數(shù),向 child 進(jìn)程發(fā)送消息,而 child 進(jìn)程使用 message 事件偵聽(tīng)這些消息。
讓我們用一個(gè)實(shí)際的例子來(lái)說(shuō)明。我們將創(chuàng)建一個(gè)簡(jiǎn)單的應(yīng)用程序,其中父進(jìn)程分叉一個(gè) child 進(jìn)程,并使用 send() 方法和 message 事件與之通信。
父文件,即 parent.js,將如下所示:
const { fork } = require("child_process");
const child = fork("./child.js");
child.send({ greeting: "Hello from parent!" });
child.on("message", (msg) => {
console.log("Message from child:", msg);
});
console.log("Waiting for response...");child 進(jìn)程文件,即 child.js:
process.on("message", (msg) => {
console.log("Message received from parent:", msg);
process.send({ response: "Hello from child!" });
});在這個(gè)例子中,父進(jìn)程向 child 進(jìn)程發(fā)送一條包含問(wèn)候語(yǔ)的消息。child 進(jìn)程偵聽(tīng)此消息,記錄它,然后向父進(jìn)程發(fā)送一條響應(yīng)。父進(jìn)程也偵聽(tīng)來(lái)自 child 進(jìn)程的傳入消息,并在收到時(shí)記錄它們。
使用 send() 和 message 事件進(jìn)行 IPC 的這種模式在需要協(xié)調(diào)父進(jìn)程和 child 進(jìn)程之間的操作時(shí)特別有用,例如共享數(shù)據(jù)、觸發(fā)操作或在 Node.js 應(yīng)用程序中實(shí)現(xiàn)請(qǐng)求-響應(yīng)模式。

管理子進(jìn)程的最佳實(shí)踐
以下是一些用于有效管理 child 進(jìn)程的最佳實(shí)踐:
監(jiān)控系統(tǒng)資源:最佳實(shí)踐之一是定期監(jiān)控系統(tǒng)的 CPU、內(nèi)存和網(wǎng)絡(luò)使用情況,以識(shí)別潛在的瓶頸或資源泄漏。使用諸如 top 和 ps 之類(lèi)的工具可以為您提供資源消耗的實(shí)時(shí)洞察。
為長(zhǎng)時(shí)間運(yùn)行的進(jìn)程設(shè)置超時(shí):使用
spawn()中的timeout選項(xiàng)自動(dòng)終止在指定持續(xù)時(shí)間后仍在運(yùn)行的child進(jìn)程。這對(duì)于避免長(zhǎng)時(shí)間運(yùn)行的活動(dòng)占用資源非常有益。實(shí)施優(yōu)雅的關(guān)閉程序:優(yōu)雅關(guān)閉程序是指服務(wù)器已響應(yīng)所有請(qǐng)求,并且沒(méi)有剩余的數(shù)據(jù)處理工作。始終確保
child進(jìn)程可以優(yōu)雅地關(guān)閉,釋放資源并執(zhí)行任何必要的清理工作。這可以通過(guò)偵聽(tīng)終止信號(hào)并相應(yīng)地響應(yīng)來(lái)實(shí)現(xiàn)。應(yīng)用 kill 方法:使用適當(dāng)?shù)男盘?hào)(例如,
SIGTERM用于優(yōu)雅關(guān)閉,SIGKILL作為最后手段)。驗(yàn)證進(jìn)程是否已成功終止。在應(yīng)用 kill 方法時(shí)處理潛在錯(cuò)誤。
子進(jìn)程與工作線程
雖然 child 進(jìn)程對(duì)某些工作很有用,但 Node.js 還提供了另一種并行執(zhí)行的方法。這種方法被稱(chēng)為工作線程,它與 child 進(jìn)程完全不同。
worker threads 模塊在 Node.js v10.50 中引入。與 child 進(jìn)程相比,它提供了一種更有效的方式來(lái)處理多線程。下面是一個(gè)突出它們差異的表格
| 特性 | 工作線程 | 子進(jìn)程 |
|---|---|---|
| 內(nèi)存隔離 | 與父進(jìn)程共享內(nèi)存空間 | 每個(gè)子進(jìn)程都有自己的內(nèi)存堆(完全隔離) |
| 通信 | 使用消息傳遞,開(kāi)銷(xiāo)較小(通過(guò) SharedArrayBuffer) | 通過(guò) IPC 通道通信,開(kāi)銷(xiāo)較大 |
| 性能 | 更輕量級(jí),頻繁數(shù)據(jù)交換的開(kāi)銷(xiāo)較低 | 通信頻繁時(shí)開(kāi)銷(xiāo)較高 |
| 用例 | 平行計(jì)算,需要頻繁數(shù)據(jù)交換的任務(wù) | CPU 密集型任務(wù),運(yùn)行外部腳本,隔離任務(wù) |
| 錯(cuò)誤隔離 | 錯(cuò)誤可能影響主線程 | 子進(jìn)程中的錯(cuò)誤不影響父進(jìn)程 |
| API 模塊 | worker_threads | child_process |
| 創(chuàng)建方法 | new Worker() | spawn(), fork(), exec(), execFile() |
| 多線程 | 真正的多線程,共享內(nèi)存 | 單獨(dú)的進(jìn)程,沒(méi)有真正的多線程 |
| 開(kāi)銷(xiāo) | 由于共享內(nèi)存而較低 | 由于完全創(chuàng)建進(jìn)程而較高 |
| 資源管理 | 在同一進(jìn)程內(nèi)管理 | 為每個(gè)進(jìn)程分配單獨(dú)的資源 |
何時(shí)使用子進(jìn)程
當(dāng)您需要完全隔離時(shí),例如運(yùn)行外部腳本或管理可能會(huì)使父進(jìn)程崩潰的 CPU 密集型任務(wù),可以使用 child 進(jìn)程。
何時(shí)使用工作線程
另一方面,當(dāng)任務(wù)從共享內(nèi)存和頻繁通信中受益時(shí),可以使用 worker 線程,例如數(shù)據(jù)處理和并行計(jì)算。
結(jié)論
child 進(jìn)程模塊有助于執(zhí)行并行任務(wù),運(yùn)行外部腳本和管理子進(jìn)程。當(dāng)您理解這些方法以及如何實(shí)現(xiàn)它們時(shí),您將能夠顯著提高應(yīng)用程序的性能和可擴(kuò)展性。
到此這篇關(guān)于Nodejs-child_process模塊解讀的文章就介紹到這了,更多相關(guān)Nodejs-child_process模塊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Node.js中的http請(qǐng)求客戶端示例(request client)
本篇文章主要介紹了Node.js中的http請(qǐng)求客戶端示例(request client),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
NodeJS 將文件夾按照存放路徑變成一個(gè)對(duì)應(yīng)的JSON的方法
這篇文章主要介紹了NodeJS 將文件夾按照存放路徑變成一個(gè)對(duì)應(yīng)的JSON的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
express框架實(shí)現(xiàn)基于Websocket建立的簡(jiǎn)易聊天室
本篇文章主要介紹了express框架實(shí)現(xiàn)基于Websocket建立的簡(jiǎn)易聊天室,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08
NodeJS學(xué)習(xí)筆記之網(wǎng)絡(luò)編程
Node.js采用了Google Chrome瀏覽器的V8引擎,性能很好,同時(shí)還提供了很多系統(tǒng)級(jí)的API,如文件操作、網(wǎng)絡(luò)編程等。Node.js則是一個(gè)全面的后臺(tái)運(yùn)行時(shí),為Javascript提供了其他語(yǔ)言能夠?qū)崿F(xiàn)的許多功能。今天我們來(lái)看下Nodejs的網(wǎng)絡(luò)編程2014-08-08
將node安裝到其他盤(pán)的超詳細(xì)步驟與說(shuō)明
基本現(xiàn)在很多主流的前端框架都用了node.js 但是node裝起來(lái)確實(shí)頭疼,下面這篇文章主要給大家介紹了關(guān)于如何將node安裝到其他盤(pán)的超詳細(xì)步驟與說(shuō)明,需要的朋友可以參考下2023-06-06
淺談node node-sass sass-loader版本對(duì)應(yīng)問(wèn)題
本文主要介紹了淺談node node-sass sass-loader版本對(duì)應(yīng)問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09

