深入浅析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

child.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:${data}`)})

登录后复制

此时就会从命令行 stdin 获取输入,当用户触发回车 + ctrl D 时就开始执行命令,并把结果从 stdout 输出。

wc 是 Word 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 = 0setInterval(() => {  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 

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

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

const longComputation = () => {  let sum = 0;  for (let i = 0; i  {  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中创建子进程的方法的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2707294.html

(0)
上一篇 2025年3月7日 20:11:10
下一篇 2025年3月2日 16:36:10

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 趣味讲解Node.js中的回调函数(附示例)

    本篇文章给大家趣讲node.js的回调函数,通过示例带大家简单了解一下回调函数,希望对大家有所帮助! 趣讲Node.js的回调函数 Node.js异步编程的直接体现就是回调函数,回调函数在完成任务后会被调用,而Node.js使用了大量的回调…

    2025年3月7日
    200
  • 浅析Node.js+Winston库如何构建简单日志功能

    本篇文章给大家介绍一下node.js中使用winston库构建一个简单日志功能的方法,希望对大家有所帮助! Winston  是强大、灵活的 Node.js 开源日志库之一,理论上, Winston  是一个可以记录所有信息的记录器。这是一…

    2025年3月7日 编程技术
    200
  • 浅谈Nodejs中要怎么做定时任务

    本篇文章给大家介绍一下node定时任务的实现方法,希望对大家有所帮助! 目前我们遇到了这样一个需求,每个用户都可以自定义定时推送,定时任务的时间配置由用户自己配置,随时修改,而不是传统的由服务器设定好时间跑定时任务。【推荐学习:《node》…

    2025年3月7日
    200
  • windows怎么卸载nodejs

    windows卸载nodejs的方法:1、在桌面左下角单击【开始】按钮,然后选择【控制面板】;2、在控制面板窗口中找到【卸载程序】,单击打开;3、找到node.js并单击右键选择【卸载】即可。 本文操作环境:Windows7系统、nodej…

    2025年3月7日 编程技术
    200
  • 怎样删除nodejs

    删除nodejs的方法:1、从“控制面板”的“卸载程序”界面中卸载node程序;2、杀死所有与节点相关的进程;3、检查环境变量以确保没有引用Nodejs或npm存在即可。 本文操作环境:Windows7系统、nodejs10.16.2版、D…

    2025年3月7日
    200
  • 命令行怎么查看nodejs版本号

    命令行查看nodejs版本号的方法:1、使用“win+r”快捷键打开“运行”窗口,输入cmd命令,点击“确定”,打开“cmd命令行窗口”;2、在cmd命令行中,使用cd命令进入node安装目录 ,执行“node -v”命令,即可查看版本号。…

    2025年3月7日 编程技术
    200
  • 怎么用nodejs运行脚本

    运行方法:1、打开cmd命令窗口,执行“node”命令进入node编辑模式,输入js脚本代码,回车运行即可。2、将js脚本代码写入js文件中,在cmd命令窗口中执行“node js文件路径”即可。 本教程操作环境:windows7系统、no…

    2025年3月7日 编程技术
    200
  • nodejs有什么优点

    nodejs的优点:1、Nodejs语法完全是js语法,只要懂js基础就可以学会Nodejs后端开发;2、处理高并发场景性能更高;3、可实现高性能服务器;4、开发周期短、开发成本低、学习成本低。 本教程操作环境:windows7系统、nod…

    2025年3月7日
    100
  • nodejs如何查看版本

    nodejs查看版本的方法:1、打开“开始”菜单,在搜索框输入“cmd”;2、在搜索结果中,点击“cmd.exe”,打开cmd命令窗口;3、使用cd命令进入nodejs安装目录;4、执行“node -v”命令即可查看版本。 本教程操作环境:…

    2025年3月7日 编程技术
    200
  • 深入浅析Node.js中的包与NPM

    本篇文章带大家了解一下node.js的包管理工具:包与npm,希望对大家有所帮助! 摘要:包与NPM Node组织了自身的核心模块,也使得第三方文件模块可以有序的编写和使用。 包与NPM Node组织了自身的核心模块,也使得第三方文件模块可…

    2025年3月7日
    100

发表回复

登录后才能评论