目錄
wc
总结
首頁 web前端 js教程 深入淺析Node.js中建立子進程的方法

深入淺析Node.js中建立子進程的方法

Oct 12, 2021 am 10:05 AM
node.js 子行程

這篇文章帶大家了解一下Node.js中的子進程,介紹Node.js中創建子進程的四種方法,希望對大家有幫助!

深入淺析Node.js中建立子進程的方法

眾所周知,Node.js 是單執行緒、非同步非阻塞的程式語言,那該如何充分利用多核心 CPU 的優勢呢?這就需要用到child_process 模組來建立子進程了,在Node.js 中,有四種方法可以建立子進程:

  • ##exec

  • execFile

  • #spawn

  • ##fork

  • 【推薦學習:《
nodejs 教學

》】上面四個方法都會回傳

ChildProcess

實例(繼承自EventEmitter),此實例有三個標準的 stdio 串流:

    ##child.stdin
  • child.stdout
  • fchild.stderr
  • 子程序生命週期內可以註冊監聽的事件有:

exit

:子程序結束時觸發,參數為code 錯誤碼和signal 中斷訊號。

close

:子程序結束並且 stdio 流被關閉時觸發,參數同

exit 事件。 disconnect

:父程序呼叫

child.disconnect() 或子程序呼叫 process.disconnect() 時觸發。 error

:子進程無法建立、或無法被殺、或發送訊息給子進程失敗時觸發。

message

:子進程透過

process.send() 發送訊息時觸發。 spawn

:當子程序建立成功時觸發(Node.js v15.1版本才加入此事件)。

exec

execFile 方法也額外提供了一個回呼函數,會在子程序終止的時候觸發。接下來進行詳細分析:exec

exec 方法用於執行 bash 命令,它的參數是一個命令字串。例如統計目前目錄下的檔案數量,用 exec 函數的寫法為:

const { exec } = require("child_process")
exec("find . -type f | wc -l", (err, stdout, stderr) => {
  if (err) return console.error(`exec error: ${err}`)
  console.log(`Number of files ${stdout}`)
})
登入後複製

exec 會新建一個子進程,然後快取它的運作結果,執行結束後呼叫回呼函數。

可能你已經想到了,exec 指令是比較危險的,假如把使用者提供的字串當作exec 函數的參數,會面臨指令列注入的風險,例如:

find . -type f | wc -l; rm -rf /;
登入後複製

另外,由於exec 會在記憶體中快取全部的輸出結果,當資料比較大的時候,spawn 會是更好的選擇。

execFile

execFile 和exec 的差別在於它並不會建立shell,而是直接執行指令,所以會更有效率一點,例如:

const { execFile } = require("child_process")
const child = execFile("node", ["--version"], (error, stdout, stderr) => {
  if (error) throw error
  console.log(stdout)
})
登入後複製

由於沒有建立shell,程式的參數會作為陣列傳入,因此具有較高的安全性。

spawn

spawn 函數和 execFile 類似,預設不會開啟shell,但差異在於execFile 會快取命令列的輸出,然後把結果傳入回呼函數中,而spawn 則是以流的方式輸出,有了流,就能非常方便的對接輸入和輸出了,例如典型的

wc

命令:

const child = spawn("wc")
process.stdin.pipe(child.stdin)
child.stdout.on("data", data => {
  console.log(`child stdout:\n${data}`)
})
登入後複製
此時就會從命令列stdin 獲取輸入,當使用者觸發回車ctrl D

時就開始執行指令,並把結果從stdout 輸出。

wc 是Wo​​rd Count 的縮寫,用於統計單字數,語法為:

wc [OPTION]... [FILE]...
登入後複製
如果在終端機上輸入wc 指令並回車,這時候統計的是從鍵盤輸入終端機中的字符,再次按回車鍵,然後按

Ctrl D

會輸出統計的結果。

透過管道還可以組合複雜的命令,例如統計當前目錄下的檔案數量,在Linux 命令列中會這麼寫:

find . -type f | wc -l
登入後複製
在Node.js 中的寫法和命令列一模一樣:

const find = spawn("find", [".", "-type", "f"])
const wc = spawn("wc", ["-l"])
find.stdout.pipe(wc.stdin)
wc.stdout.on("data", (data) => {
  console.log(`Number of files ${data}`)
})
登入後複製

spawn 有豐富的自訂配置,例如:

const child = spawn("find . -type f | wc -l", {
  stdio: "inherit", // 继承父进程的输入输出流
  shell: true, // 开启命令行模式
  cwd: "/Users/keliq/code", // 指定执行目录
  env: { ANSWER: 42 }, // 指定环境变量(默认是 process.env)
  detached: true, // 作为独立进程存在
})
登入後複製

fork

fork 函數是spawn 函數的變體,使用fork 建立的子行程和父行程之間會自動建立一個通訊通道,子行程的全域物件process 上面會掛載send 方法。例如父進程parent.js 程式碼:

const { fork } = require("child_process")
const forked = fork("./child.js")

forked.on("message", msg => {
  console.log("Message from child", msg);
})

forked.send({ hello: "world" })
登入後複製

子進程child.js 程式碼:

process.on("message", msg => {
  console.log("Message from parent:", msg)
})

let counter = 0
setInterval(() => {
  process.send({ counter: counter++ })
}, 1000)
登入後複製

當呼叫

fork("child.js")

的時候,實際上就是用node 來執行該檔案中的程式碼,相當於

spawn('node', ['./child.js'])fork 的一個典型的應用場景如下:假如現在用 Node.js 建立一個 http 服務,當路由為 compute

的時候,執行一個耗時的運算。

const http = require("http")
const server = http.createServer()
server.on("request", (req, res) => {
  if (req.url === "/compute") {
    const sum = longComputation()
    return res.end(Sum is ${sum})
  } else {
    res.end("OK")
  }
})

server.listen(3000);
登入後複製
可以用下面的程式碼來模擬該耗時的運算:
const longComputation = () => {
  let sum = 0;
  for (let i = 0; i < 1e9; i++) {
    sum += i
  }
  return sum
}
登入後複製

那么在上线后,只要服务端收到了 compute 请求,由于 Node.js 是单线程的,耗时运算占用了 CPU,用户的其他请求都会阻塞在这里,表现出来的现象就是服务器无响应。

解决这个问题最简单的方法就是把耗时运算放到子进程中去处理,例如创建一个 compute.js 的文件,代码如下:

const longComputation = () => {
  let sum = 0;
  for (let i = 0; i < 1e9; i++) {
    sum += i;
  }
  return sum
}

process.on("message", msg => {
  const sum = longComputation()
  process.send(sum)
})
登入後複製

再把服务端的代码稍作改造:

const http = require("http")
const { fork } = require("child_process")
const server = http.createServer()
server.on("request", (req, res) => {
  if (req.url === "/compute") {
    const compute = fork("compute.js")
    compute.send("start")
    compute.on("message", sum => {
      res.end(Sum is ${sum})
    })
  } else {
    res.end("OK")
  }
})
server.listen(3000)
登入後複製

这样的话,主线程就不会阻塞,而是继续处理其他的请求,当耗时运算的结果返回后,再做出响应。其实更简单的处理方式是利用 cluster 模块,限于篇幅原因,后面再展开讲。

总结

掌握了上面四种创建子进程的方法之后,总结了以下三条规律:

  • 创建 node 子进程用 fork,因为自带通道方便通信。
  • 创建非 node 子进程用 execFile 或 spawn。如果输出内容较少用 execFile,会缓存结果并传给回调方便处理;如果输出内容多用 spawn,使用流的方式不会占用大量内存。
  • 执行复杂的、固定的终端命令用 exec,写起来更方便。但一定要记住 exec 会创建 shell,效率不如 execFile 和 spawn,且存在命令行注入的风险。

更多编程相关知识,请访问:编程视频!!

以上是深入淺析Node.js中建立子進程的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1322
25
PHP教程
1270
29
C# 教程
1250
24
圖文詳解Node V8引擎的記憶體和GC 圖文詳解Node V8引擎的記憶體和GC Mar 29, 2023 pm 06:02 PM

這篇文章帶大家深入了解NodeJS V8引擎的記憶體和垃圾回收器(GC),希望對大家有幫助!

一文聊聊Node中的記憶體控制 一文聊聊Node中的記憶體控制 Apr 26, 2023 pm 05:37 PM

基於無阻塞、事件驅動建立的Node服務,具有記憶體消耗低的優點,非常適合處理海量的網路請求。在海量請求的前提下,就需要考慮「記憶體控制」的相關問題了。 1. V8的垃圾回收機制與記憶體限制 Js由垃圾回收機

聊聊如何選擇一個最好的Node.js Docker映像? 聊聊如何選擇一個最好的Node.js Docker映像? Dec 13, 2022 pm 08:00 PM

選擇一個Node的Docker映像看起來像是小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?

Node.js 19正式發布,聊聊它的 6 大功能! Node.js 19正式發布,聊聊它的 6 大功能! Nov 16, 2022 pm 08:34 PM

Node 19已正式發布,以下這篇文章就來帶大家詳解了解Node.js 19的 6 大特性,希望對大家有幫助!

深入聊聊Node中的File模組 深入聊聊Node中的File模組 Apr 24, 2023 pm 05:49 PM

文件模組是對底層文件操作的封裝,例如文件讀寫/打開關閉/刪除添加等等文件模組最大的特點就是所有的方法都提供的**同步**和**異步**兩個版本,具有sync 字尾的方法都是同步方法,沒有的都是異

一起聊聊Node中的事件循環 一起聊聊Node中的事件循環 Apr 11, 2023 pm 07:08 PM

事件循環是 Node.js 的基本組成部分,透過確保主執行緒不被阻塞來實現非同步編程,了解事件循環對建立高效應用程式至關重要。以下這篇文章就來帶大家深入了解Node中的事件循環 ,希望對大家有幫助!

聊聊用pkg將Node.js專案打包為執行檔的方法 聊聊用pkg將Node.js專案打包為執行檔的方法 Dec 02, 2022 pm 09:06 PM

如何用pkg打包nodejs可執行檔?以下這篇文章跟大家介紹一下使用pkg將Node專案打包為執行檔的方法,希望對大家有幫助!

node無法用npm指令怎麼辦 node無法用npm指令怎麼辦 Feb 08, 2023 am 10:09 AM

node無法用npm指令是因為沒有正確配置環境變量,其解決方法是:1、開啟“系統屬性”;2、找到“環境變數”->“系統變數”,然後編輯環境變數;3、找到nodejs所在的資料夾;4、點選「確定」即可。

See all articles