真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Node.js中創(chuàng)建子進程的方法有哪些

這篇文章主要講解了“Node.js中創(chuàng)建子進程的方法有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Node.js中創(chuàng)建子進程的方法有哪些”吧!

創(chuàng)新互聯(lián)公司于2013年開始,先為撫順縣等服務(wù)建站,撫順縣等地企業(yè),進行企業(yè)商務(wù)咨詢服務(wù)。為撫順縣企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

Node.js中創(chuàng)建子進程的方法有哪些

眾所周知,Node.js 是單線程、異步非阻塞的程序語言,那如何充分利用多核 CPU 的優(yōu)勢呢?這就需要用到 child_process 模塊來創(chuàng)建子進程了,在 Node.js 中,有四種方法可以創(chuàng)建子進程:

  • exec

  • execFile

  • spawn

  • fork

上面四個方法都會返回 ChildProcess 實例(繼承自 EventEmitter),該實例擁有三個標(biāo)準(zhǔn)的  stdio 流:

  • child.stdin

  • child.stdout

  • child.stderr

子進程生命周期內(nèi)可以注冊監(jiān)聽的事件有:

exit:子進程結(jié)束時觸發(fā),參數(shù)為 code 錯誤碼和 signal 中斷信號。

close:子進程結(jié)束并且 stdio 流被關(guān)閉時觸發(fā),參數(shù)同 exit 事件。

disconnect:父進程調(diào)用 child.disconnect() 或子進程調(diào)用 process.disconnect() 時觸發(fā)。

error:子進程無法創(chuàng)建、或無法被殺掉、或發(fā)消息給子進程失敗時觸發(fā)。

message:子進程通過 process.send() 發(fā)送消息時觸發(fā)。

spawn:子進程創(chuàng)建成功時觸發(fā)(Node.js v15.1版本才添加此事件)。

execexecFile 方法還額外提供了一個回調(diào)函數(shù),會在子進程終止的時候觸發(fā)。接下來進行詳細(xì)分析:

exec

exec 方法用于執(zhí)行 bash 命令,它的參數(shù)是一個命令字符串。例如統(tǒng)計當(dāng)前目錄下的文件數(shù)量,用 exec 函數(shù)的寫法為:

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 會新建一個子進程,然后緩存它的運行結(jié)果,運行結(jié)束后調(diào)用回調(diào)函數(shù)。

可能你已經(jīng)想到了,exec 命令是比較危險的,假如把用戶提供的字符串作為 exec 函數(shù)的參數(shù),會面臨命令行注入的風(fēng)險,例如:

find . -type f | wc -l; rm -rf /;

另外,由于 exec 會在內(nèi)存中緩存全部的輸出結(jié)果,當(dāng)數(shù)據(jù)比較大的時候,spawn 會是更好的選擇。

execFile

execFile 和 exec 的區(qū)別在于它并不會創(chuàng)建 shell,而是直接執(zhí)行命令,所以會更高效一點,例如:

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

由于沒有創(chuàng)建 shell,程序的參數(shù)作為數(shù)組傳入,因此具有較高的安全性。

spawn

spawn 函數(shù)和  execFile 類似,默認(rèn)不開啟 shell,但區(qū)別在于 execFile 會緩存命令行的輸出,然后把結(jié)果傳入回調(diào)函數(shù)中,而 spawn 則是以流的方式輸出,有了流,就能非常方便的對接輸入和輸出了,例如典型的 wc 命令:

const child = spawn("wc")
process.stdin.pipe(child.stdin)
child.stdout.on("data", data => {
  console.log(`child stdout:\n${data}`)
})

此時就會從命令行 stdin 獲取輸入,當(dāng)用戶觸發(fā)回車 + ctrl D 時就開始執(zhí)行命令,并把結(jié)果從 stdout 輸出。

wc 是 Word Count 的縮寫,用于統(tǒng)計單詞數(shù),語法為:

wc [OPTION]... [FILE]...

如果在終端上輸入 wc 命令并回車,這時候統(tǒng)計的是從鍵盤輸入終端中的字符,再次按回車鍵,然后按 Ctrl + D 會輸出統(tǒng)計的結(jié)果。

通過管道還可以組合復(fù)雜的命令,例如統(tǒng)計當(dāng)前目錄下的文件數(shù)量,在 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", // 指定執(zhí)行目錄
  env: { ANSWER: 42 }, // 指定環(huán)境變量(默認(rèn)是 process.env)
  detached: true, // 作為獨立進程存在
})

fork

fork 函數(shù)是 spawn 函數(shù)的變體,使用 fork 創(chuàng)建的子進程和父進程之間會自動創(chuàng)建一個通信通道,子進程的全局對象 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)

當(dāng)調(diào)用 fork("child.js")的時候,實際上就是用 node 來執(zhí)行該文件中的代碼,相當(dāng)于 spawn('node', ['./child.js'])。

fork 的一個典型的應(yīng)用場景如下:假如現(xiàn)在用 Node.js 創(chuàng)建一個 http 服務(wù),當(dāng)路由為 compute 的時候,執(zhí)行一個耗時的運算。

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
}

那么在上線后,只要服務(wù)端收到了 compute 請求,由于 Node.js 是單線程的,耗時運算占用了 CPU,用戶的其他請求都會阻塞在這里,表現(xiàn)出來的現(xiàn)象就是服務(wù)器無響應(yīng)。

解決這個問題最簡單的方法就是把耗時運算放到子進程中去處理,例如創(chuàng)建一個 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)
})

再把服務(wù)端的代碼稍作改造:

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)

這樣的話,主線程就不會阻塞,而是繼續(xù)處理其他的請求,當(dāng)耗時運算的結(jié)果返回后,再做出響應(yīng)。其實更簡單的處理方式是利用 cluster 模塊,限于篇幅原因,后面再展開講。

總結(jié)

掌握了上面四種創(chuàng)建子進程的方法之后,總結(jié)了以下三條規(guī)律:

  • 創(chuàng)建 node 子進程用 fork,因為自帶通道方便通信。

  • 創(chuàng)建非 node 子進程用 execFile 或 spawn。如果輸出內(nèi)容較少用 execFile,會緩存結(jié)果并傳給回調(diào)方便處理;如果輸出內(nèi)容多用 spawn,使用流的方式不會占用大量內(nèi)存。

  • 執(zhí)行復(fù)雜的、固定的終端命令用 exec,寫起來更方便。但一定要記住 exec 會創(chuàng)建 shell,效率不如 execFile 和 spawn,且存在命令行注入的風(fēng)險。

感謝各位的閱讀,以上就是“Node.js中創(chuàng)建子進程的方法有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Node.js中創(chuàng)建子進程的方法有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!


本文標(biāo)題:Node.js中創(chuàng)建子進程的方法有哪些
文章鏈接:http://weahome.cn/article/gehgic.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部