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)行各種語言的腳本,甚至可以創(chuàng)建新的 Node.js 實(shí)例。
child
進(jìn)程模塊的主要目的是允許同時(shí)執(zhí)行多個(gè)進(jìn)程,而不會(huì)阻塞主事件循環(huán)。
對(duì)于需要處理 CPU 密集型操作或執(zhí)行外部命令和腳本的應(yīng)用來說,使用 child
進(jìn)程可以確保應(yīng)用的高性能和響應(yīng)性。
子進(jìn)程的使用方式
child
進(jìn)程可以用于以下任務(wù):
并行處理:
Child
處理通過允許應(yīng)用程序?qū)⒐ぷ髫?fù)載分布在多個(gè) CPU 核心上,從而顯著提高 CPU 密集型活動(dòng)(如圖像處理和數(shù)據(jù)分析)的性能。運(yùn)行 shell 腳本:
Child
進(jìn)程可以用來執(zhí)行 shell 腳本。您可以使用exec
技術(shù)來運(yùn)行 shell 命令并捕獲它們的輸出,還可以使用spawn
方法,當(dāng)直接運(yùn)行腳本時(shí)提供更大的控制。與其他服務(wù)通信:在通信方面,
child
進(jìn)程起著至關(guān)重要的作用。它可以與外部服務(wù)(如數(shù)據(jù)庫、API 或微服務(wù))進(jìn)行通信。它們可以用來調(diào)用外部 API,執(zhí)行數(shù)據(jù)庫查詢,與其它微服務(wù)通信。
創(chuàng)建子進(jìn)程
要?jiǎng)?chuàng)建一個(gè) child
進(jìn)程,Node.js 為我們提供了四種主要方法來創(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 命令,解析其輸出,并顯示總的、已用的和可用的磁盤空間以及使用百分比。
運(yùn)行代碼時(shí),您應(yīng)該會(huì)看到類似這樣的內(nèi)容:
execFile()
方法
execFile()
方法在沒有 shell 的情況下運(yùn)行可執(zhí)行文件。它比 exec()
更高效,因?yàn)樗苊饬?shell 的開銷。
下面是一個(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í)行文件來獲取其版本。當(dāng)命令不需要 shell 特性時(shí),推薦使用 execFile()
。
spawn()
方法
與主要用于執(zhí)行 shell 命令或可執(zhí)行文件并捕獲其輸出的 exec
方法不同,spawn()
方法通過基于流的輸出處理、直接與可執(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
命令并附加事件偵聽器來處理進(jìn)程的輸出和退出狀態(tài)。
運(yùn)行代碼時(shí),您應(yīng)該會(huì)看到類似這樣的內(nèi)容:
fork()
方法
fork()
方法可以說是為創(chuàng)建新的 Node.js 進(jìn)程而設(shè)計(jì)的 spawn()
的變體。與可以啟動(dòng)任何類型進(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ì)看到類似這樣的內(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è)通道;如果需要,開發(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ù)專門用于需要生成工作進(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ì)象添加事件偵聽器,以在 stdout
和 stderr
上的 data
事件上。
Node.js 提供了幾種特別有用的事件偵聽器,用于處理 child
進(jìn)程輸出和錯(cuò)誤。其中包括:
Data
:數(shù)據(jù)事件由代表子進(jìn)程的 stdout 和 stderr 的流發(fā)出。Error
:
當(dāng)child
進(jìn)程執(zhí)行過程中發(fā)生錯(cuò)誤時(shí),會(huì)觸發(fā)錯(cuò)誤事件。這可能是由于命令本身的問題,或者是讀取stdout
或stderr
時(shí)出現(xiàn)問題。Close
:當(dāng)child
進(jìn)程結(jié)束時(shí),會(huì)發(fā)出關(guān)閉事件,表明它是否成功終止或被殺死。
讓我們看一個(gè)示例,展示如何生成一個(gè) child
進(jìn)程,捕獲其輸出,并處理可能發(fā)生的任何錯(cuò)誤。
我們將使用 spawn()
方法來啟動(dòng)一個(gè)簡(jiǎn)單的命令(echo
)并偵聽輸出和錯(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)程來執(zhí)行 echo
命令,該命令簡(jiǎn)單地將 Hello, world!
打印到終端。
父進(jìn)程通過附加到 stdout
和 stderr
的 data
事件偵聽器來捕獲此輸出。此外,它還偵聽 error
事件以捕獲在執(zhí)行 child
進(jìn)程期間可能發(fā)生的任何錯(cuò)誤。
最后,close
事件指示 child
進(jìn)程已完成執(zhí)行,以及退出代碼,這可以用來確定進(jìn)程是否成功完成。
進(jìn)程間通信
在分布式系統(tǒng)和并發(fā)編程中,進(jìn)程間通信對(duì)于組件協(xié)調(diào)至關(guān)重要。Node.js 通過其 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è)突出的方法是通過 send()
方法和 message
事件進(jìn)行消息傳遞。這種方法利用了 child
進(jìn)程對(duì)象上可用的 send()
函數(shù),向 child
進(jìn)程發(fā)送消息,而 child
進(jìn)程使用 message
事件偵聽這些消息。
讓我們用一個(gè)實(shí)際的例子來說明。我們將創(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ā)送一條包含問候語的消息。child
進(jìn)程偵聽此消息,記錄它,然后向父進(jìn)程發(fā)送一條響應(yīng)。父進(jìn)程也偵聽來自 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 之類的工具可以為您提供資源消耗的實(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)求,并且沒有剩余的數(shù)據(jù)處理工作。始終確保
child
進(jìn)程可以優(yōu)雅地關(guān)閉,釋放資源并執(zhí)行任何必要的清理工作。這可以通過偵聽終止信號(hào)并相應(yīng)地響應(yīng)來實(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í)行的方法。這種方法被稱為工作線程,它與 child
進(jìn)程完全不同。
worker threads
模塊在 Node.js v10.50 中引入。與 child
進(jìn)程相比,它提供了一種更有效的方式來處理多線程。下面是一個(gè)突出它們差異的表格
特性 | 工作線程 | 子進(jìn)程 |
---|---|---|
內(nèi)存隔離 | 與父進(jìn)程共享內(nèi)存空間 | 每個(gè)子進(jìn)程都有自己的內(nèi)存堆(完全隔離) |
通信 | 使用消息傳遞,開銷較?。ㄍㄟ^ SharedArrayBuffer) | 通過 IPC 通道通信,開銷較大 |
性能 | 更輕量級(jí),頻繁數(shù)據(jù)交換的開銷較低 | 通信頻繁時(shí)開銷較高 |
用例 | 平行計(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)程,沒有真正的多線程 |
開銷 | 由于共享內(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-05NodeJS 將文件夾按照存放路徑變成一個(gè)對(duì)應(yīng)的JSON的方法
這篇文章主要介紹了NodeJS 將文件夾按照存放路徑變成一個(gè)對(duì)應(yīng)的JSON的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-10-10express框架實(shí)現(xiàn)基于Websocket建立的簡(jiǎn)易聊天室
本篇文章主要介紹了express框架實(shí)現(xiàn)基于Websocket建立的簡(jiǎn)易聊天室,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08NodeJS學(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提供了其他語言能夠?qū)崿F(xiàn)的許多功能。今天我們來看下Nodejs的網(wǎng)絡(luò)編程2014-08-08淺談node node-sass sass-loader版本對(duì)應(yīng)問題
本文主要介紹了淺談node node-sass sass-loader版本對(duì)應(yīng)問題,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09