ホームページ >ウェブフロントエンド >jsチュートリアル >Node.js で子プロセスを作成する方法の詳細な分析
この記事では、Node.js のサブプロセスを理解し、Node.js でサブプロセスを作成する 4 つの方法を紹介します。皆様のお役に立てれば幸いです。
ご存知のとおり、Node.js はシングルスレッド、非同期、ノンブロッキングのプログラミング言語です。 CPU?これには、子プロセスを作成するための child_process モジュールが必要です。Node.js では、子プロセスを作成するには 4 つの方法があります:
exec
execFile
##spawn
fork
nodejs チュートリアル "]
上記 4 つのメソッドはChildProcess を返します インスタンス (
EventEmitter から継承)。これには 3 つの標準 stdio ストリームがあります:
child.stdin
child.stdout
: 子プロセスの終了時にトリガーされ、パラメータはコード エラー コードとシグナル割り込みシグナルです。
: 子プロセスが終了し、stdio ストリームが閉じられるとトリガーされます。パラメータは exit
イベントと同じです。
: 親プロセスが child.disconnect()
を呼び出すか、子プロセスが process.disconnect()
を呼び出すとトリガーされます。
: 子プロセスを作成できない場合、強制終了できない場合、または子プロセスへのメッセージの送信に失敗した場合にトリガーされます。
: 子プロセスが process.send()
を通じてメッセージを送信するとトリガーされます。
: 子プロセスが正常に作成されたときにトリガーされます (このイベントは Node.js v15.1 でのみ追加されました)。
メソッドと execFile
メソッドは、子プロセスの終了時にトリガーされる追加のコールバック関数も提供します。次に、詳細な分析を行います。 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 の方が適切な選択肢になります。 execFileexecFile と exec の違いは、シェルを作成せず、コマンドを直接実行するため、より効率的です。例:
const { execFile } = require("child_process") const child = execFile("node", ["--version"], (error, stdout, stderr) => { if (error) throw error console.log(stdout) })
const child = spawn("wc") process.stdin.pipe(child.stdin) child.stdout.on("data", data => { console.log(`child stdout:\n${data}`) })
このとき、入力はユーザーが復帰
ctrl D をトリガーすると、コマンドの実行が開始され、結果が標準出力から出力されます。 wc は Word Count の略語で、単語数をカウントするために使用されます。構文は次のとおりです:
wc [OPTION]... [FILE]...
ターミナルで wc コマンドを入力して Enter キーを押すと、 、カウントはキーボードからのものです。ターミナルに文字を入力し、もう一度 Enter キーを押し、Node.js での記述方法 コマンド ラインとまったく同じです:Ctrl D
を押して統計結果を出力します。
現在のディレクトリ内のファイル数を数えるなど、パイプラインを介して複雑なコマンドを組み合わせることができます。Linux コマンド ラインでは、次のように記述されます:
find . -type f | wc -l
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 関数は次のとおりです。 fork によって作成された子を使用する spawn 関数のバリアント。プロセスと親プロセスの間に通信チャネルが自動的に作成され、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" })
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.js で子プロセスを作成する方法の詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。