Nodejs-child_process模塊詳細介紹
在 Node.js 應(yīng)用程序中,child 進程模塊非常重要,有了它可以實現(xiàn)并行處理,這在資源密集型任務(wù)里十分重要。
在本文中,我們將看一下 child 進程模塊,解釋其目的、使用方式以及如何使用。
什么是子進程模塊
子進程是核心模塊,允許用戶創(chuàng)建和控制子進程。這些進程可以執(zhí)行系統(tǒng)命令、運行各種語言的腳本,甚至可以創(chuàng)建新的 Node.js 實例。
child 進程模塊的主要目的是允許同時執(zhí)行多個進程,而不會阻塞主事件循環(huán)。
對于需要處理 CPU 密集型操作或執(zhí)行外部命令和腳本的應(yīng)用來說,使用 child 進程可以確保應(yīng)用的高性能和響應(yīng)性。
子進程的使用方式
child 進程可以用于以下任務(wù):
并行處理:
Child處理通過允許應(yīng)用程序?qū)⒐ぷ髫撦d分布在多個 CPU 核心上,從而顯著提高 CPU 密集型活動(如圖像處理和數(shù)據(jù)分析)的性能。運行 shell 腳本:
Child進程可以用來執(zhí)行 shell 腳本。您可以使用exec技術(shù)來運行 shell 命令并捕獲它們的輸出,還可以使用spawn方法,當(dāng)直接運行腳本時提供更大的控制。與其他服務(wù)通信:在通信方面,
child進程起著至關(guān)重要的作用。它可以與外部服務(wù)(如數(shù)據(jù)庫、API 或微服務(wù))進行通信。它們可以用來調(diào)用外部 API,執(zhí)行數(shù)據(jù)庫查詢,與其它微服務(wù)通信。
創(chuàng)建子進程
要創(chuàng)建一個 child 進程,Node.js 為我們提供了四種主要方法來創(chuàng)建一個 child 進程,分別是 exec(), execFile(), spawn(), fork()
exec() 方法
exec() 方法在 shell 中運行一個命令并緩沖輸出。它適用于運行 shell 命令并記錄輸出。但由于是緩沖,它有內(nèi)存限制。
下面是一個使用 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 命令,解析其輸出,并顯示總的、已用的和可用的磁盤空間以及使用百分比。
運行代碼時,您應(yīng)該會看到類似這樣的內(nèi)容:

execFile() 方法
execFile() 方法在沒有 shell 的情況下運行可執(zhí)行文件。它比 exec() 更高效,因為它避免了 shell 的開銷。
下面是一個如何使用 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}`);
});這個例子展示了運行 Node.js 可執(zhí)行文件來獲取其版本。當(dāng)命令不需要 shell 特性時,推薦使用 execFile()。
spawn() 方法
與主要用于執(zhí)行 shell 命令或可執(zhí)行文件并捕獲其輸出的 exec 方法不同,spawn() 方法通過基于流的輸出處理、直接與可執(zhí)行文件交互、事件驅(qū)動的通信,提供了對 child 進程的更多控制。
spawn() 方法可用于需要直接交互的復(fù)雜場景。spawn() 啟動一個新進程,給定一個命令,并提供流 i.e stdout, stderr 用于直接處理進程的輸出和錯誤。
下面是一個如何使用 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]`);
});在這個例子中,spawn() 運行 ls 命令并附加事件偵聽器來處理進程的輸出和退出狀態(tài)。
運行代碼時,您應(yīng)該會看到類似這樣的內(nèi)容:

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

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

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

