Nodejs-child_process模塊詳細介紹
在 Node.js 應用程序中,child
進程模塊非常重要,有了它可以實現(xiàn)并行處理,這在資源密集型任務里十分重要。
在本文中,我們將看一下 child
進程模塊,解釋其目的、使用方式以及如何使用。
什么是子進程模塊
子進程是核心模塊,允許用戶創(chuàng)建和控制子進程。這些進程可以執(zhí)行系統(tǒng)命令、運行各種語言的腳本,甚至可以創(chuàng)建新的 Node.js 實例。
child
進程模塊的主要目的是允許同時執(zhí)行多個進程,而不會阻塞主事件循環(huán)。
對于需要處理 CPU 密集型操作或執(zhí)行外部命令和腳本的應用來說,使用 child
進程可以確保應用的高性能和響應性。
子進程的使用方式
child
進程可以用于以下任務:
并行處理:
Child
處理通過允許應用程序將工作負載分布在多個 CPU 核心上,從而顯著提高 CPU 密集型活動(如圖像處理和數據分析)的性能。運行 shell 腳本:
Child
進程可以用來執(zhí)行 shell 腳本。您可以使用exec
技術來運行 shell 命令并捕獲它們的輸出,還可以使用spawn
方法,當直接運行腳本時提供更大的控制。與其他服務通信:在通信方面,
child
進程起著至關重要的作用。它可以與外部服務(如數據庫、API 或微服務)進行通信。它們可以用來調用外部 API,執(zhí)行數據庫查詢,與其它微服務通信。
創(chuàng)建子進程
要創(chuàng)建一個 child
進程,Node.js 為我們提供了四種主要方法來創(chuàng)建一個 child
進程,分別是 exec()
, execFile()
, spawn()
, fork()
exec()
方法
exec()
方法在 shell 中運行一個命令并緩沖輸出。它適用于運行 shell 命令并記錄輸出。但由于是緩沖,它有內存限制。
下面是一個使用 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 命令,解析其輸出,并顯示總的、已用的和可用的磁盤空間以及使用百分比。
運行代碼時,您應該會看到類似這樣的內容:
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í)行文件來獲取其版本。當命令不需要 shell 特性時,推薦使用 execFile()
。
spawn()
方法
與主要用于執(zhí)行 shell 命令或可執(zhí)行文件并捕獲其輸出的 exec
方法不同,spawn()
方法通過基于流的輸出處理、直接與可執(zhí)行文件交互、事件驅動的通信,提供了對 child
進程的更多控制。
spawn()
方法可用于需要直接交互的復雜場景。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)。
運行代碼時,您應該會看到類似這樣的內容:
fork()
方法
fork()
方法可以說是為創(chuàng)建新的 Node.js 進程而設計的 spawn()
的變體。與可以啟動任何類型進程的 spawn()
不同,fork()
方法針對創(chuàng)建本身是 Node.js 應用程序的 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 事件在父進程和子進程之間傳遞消息。
當您運行代碼時,您應該會看到類似這樣的內容:
fork()
與 spawn()
之間的區(qū)別
fork
和 spawn
之間的一些區(qū)別包括:
內置通信通道:
fork()
在父進程和child
進程之間自動設置了一個 IPC(進程間通信)通道。相比之下,spawn()
默認不建立這個通道;如果需要,開發(fā)人員必須手動配置 IPC。隔離和獨立性:每個由
fork()
生成的child
進程都是一個單獨的 Node.js 進程,擁有自己的 V8 實例。另一方面,spawn()
方法可以啟動任何進程,包括 Node.js 應用程序,并不提供相同級別的隔離。用例特異性:
fork()
技術專門用于需要生成工作進程的情況,這些工作進程是同一應用程序的一部分,但同時運行。相比之下,spawn()
更為通用,用于需要啟動 Node.js 生態(tài)系統(tǒng)之外的任意命令或腳本時。
處理子進程輸出
當創(chuàng)建一個 child
進程時,它會在兩個主要流中產生輸出:stdout
和 stderr
。這些流保存了由 child
進程運行的命令或腳本的結果。要收集此輸出,請為 child
進程對象添加事件偵聽器,以在 stdout
和 stderr
上的 data
事件上。
Node.js 提供了幾種特別有用的事件偵聽器,用于處理 child
進程輸出和錯誤。其中包括:
Data
:數據事件由代表子進程的 stdout 和 stderr 的流發(fā)出。Error
:
當child
進程執(zhí)行過程中發(fā)生錯誤時,會觸發(fā)錯誤事件。這可能是由于命令本身的問題,或者是讀取stdout
或stderr
時出現(xiàn)問題。Close
:當child
進程結束時,會發(fā)出關閉事件,表明它是否成功終止或被殺死。
讓我們看一個示例,展示如何生成一個 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é)調至關重要。Node.js 通過其 child
進程模塊改進了這種通信。這使您能夠創(chuàng)建 child
進程并促進進程間通信(IPC)。
這種 IPC 機制,特點是父進程和 child
進程之間交換數據,對于構建模塊化和可擴展的應用程序至關重要。
有幾種方法可以促進;一個突出的方法是通過 send()
方法和 message
事件進行消息傳遞。這種方法利用了 child
進程對象上可用的 send()
函數,向 child
進程發(fā)送消息,而 child
進程使用 message
事件偵聽這些消息。
讓我們用一個實際的例子來說明。我們將創(chuà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ā)送一條響應。父進程也偵聽來自 child
進程的傳入消息,并在收到時記錄它們。
使用 send()
和 message
事件進行 IPC 的這種模式在需要協(xié)調父進程和 child
進程之間的操作時特別有用,例如共享數據、觸發(fā)操作或在 Node.js 應用程序中實現(xiàn)請求-響應模式。
管理子進程的最佳實踐
以下是一些用于有效管理 child
進程的最佳實踐:
監(jiān)控系統(tǒng)資源:最佳實踐之一是定期監(jiān)控系統(tǒng)的 CPU、內存和網絡使用情況,以識別潛在的瓶頸或資源泄漏。使用諸如 top 和 ps 之類的工具可以為您提供資源消耗的實時洞察。
為長時間運行的進程設置超時:使用
spawn()
中的timeout
選項自動終止在指定持續(xù)時間后仍在運行的child
進程。這對于避免長時間運行的活動占用資源非常有益。實施優(yōu)雅的關閉程序:優(yōu)雅關閉程序是指服務器已響應所有請求,并且沒有剩余的數據處理工作。始終確保
child
進程可以優(yōu)雅地關閉,釋放資源并執(zhí)行任何必要的清理工作。這可以通過偵聽終止信號并相應地響應來實現(xiàn)。應用 kill 方法:使用適當的信號(例如,
SIGTERM
用于優(yōu)雅關閉,SIGKILL
作為最后手段)。驗證進程是否已成功終止。在應用 kill 方法時處理潛在錯誤。
子進程與工作線程
雖然 child
進程對某些工作很有用,但 Node.js 還提供了另一種并行執(zhí)行的方法。這種方法被稱為工作線程,它與 child
進程完全不同。
worker threads
模塊在 Node.js v10.50 中引入。與 child
進程相比,它提供了一種更有效的方式來處理多線程。下面是一個突出它們差異的表格
特性 | 工作線程 | 子進程 |
---|---|---|
內存隔離 | 與父進程共享內存空間 | 每個子進程都有自己的內存堆(完全隔離) |
通信 | 使用消息傳遞,開銷較小(通過 SharedArrayBuffer) | 通過 IPC 通道通信,開銷較大 |
性能 | 更輕量級,頻繁數據交換的開銷較低 | 通信頻繁時開銷較高 |
用例 | 平行計算,需要頻繁數據交換的任務 | CPU 密集型任務,運行外部腳本,隔離任務 |
錯誤隔離 | 錯誤可能影響主線程 | 子進程中的錯誤不影響父進程 |
API 模塊 | worker_threads | child_process |
創(chuàng)建方法 | new Worker() | spawn() , fork() , exec() , execFile() |
多線程 | 真正的多線程,共享內存 | 單獨的進程,沒有真正的多線程 |
開銷 | 由于共享內存而較低 | 由于完全創(chuàng)建進程而較高 |
資源管理 | 在同一進程內管理 | 為每個進程分配單獨的資源 |
何時使用子進程
當您需要完全隔離時,例如運行外部腳本或管理可能會使父進程崩潰的 CPU 密集型任務,可以使用 child
進程。
何時使用工作線程
另一方面,當任務從共享內存和頻繁通信中受益時,可以使用 worker
線程,例如數據處理和并行計算。
結論
child
進程模塊有助于執(zhí)行并行任務,運行外部腳本和管理子進程。當您理解這些方法以及如何實現(xiàn)它們時,您將能夠顯著提高應用程序的性能和可擴展性。
到此這篇關于Nodejs-child_process模塊解讀的文章就介紹到這了,更多相關Nodejs-child_process模塊內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Node.js中的http請求客戶端示例(request client)
本篇文章主要介紹了Node.js中的http請求客戶端示例(request client),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05NodeJS 將文件夾按照存放路徑變成一個對應的JSON的方法
這篇文章主要介紹了NodeJS 將文件夾按照存放路徑變成一個對應的JSON的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-10-10express框架實現(xiàn)基于Websocket建立的簡易聊天室
本篇文章主要介紹了express框架實現(xiàn)基于Websocket建立的簡易聊天室,具有一定的參考價值,有興趣的可以了解一下2017-08-08淺談node node-sass sass-loader版本對應問題
本文主要介紹了淺談node node-sass sass-loader版本對應問題,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09