nodejs 子线程,node 子线程

  nodejs 子线程,node 子线程

  本文带你了解Node.js中的子流程,介绍Node.js中创建子流程的四种方法,希望对你有帮助!

  node.js速度课程简介:进入学习

  众所周知,Node.js是单线程、异步、非阻塞的编程语言,那么如何充分利用多核CPU的优势呢?这需要child_process模块创建一个子进程。在Node.js中,有四种方法可以创建子流程:

  高级管理人员

  execFile

  卵

  叉

  [推荐研究:《nodejs 教程》]

  以上四个方法都返回一个ChildProcess实例(继承自EventEmitter),它有三个标准的stdio流:

  儿童标准输入

  child.stdout

  儿童标准错误

  在子流程生命周期中可以注册监听的事件有:

  Exit:子进程结束时触发,参数为code error code和signal interrupt signal。

  Close:当子进程结束且stdio流关闭时触发,参数与exit事件相同。

  Disconnect:当父进程调用child.disconnect()或子进程调用process.disconnect()时触发。

  错误:当无法创建或终止子进程,或者向子进程发送消息失败时触发。

  Message:当子流程通过process.send()发送消息时触发。

  Spawn:成功创建子流程时触发(此事件仅在Node.js v15.1的V15.1版中添加

  exec和execFile方法还提供了一个额外的回调函数,该函数将在子进程终止时被触发。接下来做一个详细的分析:

  

exec

   exec方法用于执行bash命令,其参数为命令字符串。例如,为了计算当前目录中的文件数,exec函数编写如下:

  const { exec }=require( child _ process )

  exec(find。-type f wc -l ,(err,stdout,stderr)={

  if (err)返回console . error(` exec error:$ { err } `)

  console.log(`文件数{ stdout } `)

  })exec会创建一个新的子进程,然后缓存它的运行结果,运行结束后调用回调函数。

  您可能已经想到,exec命令是危险的。如果你使用用户提供的字符串作为exec函数的参数,你将面临命令行注入的风险,比如:

  找到。-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)抛出错误

  console.log(标准输出)

  })因为没有创建shell,所以程序的参数是以数组的形式传入的,所以安全性高。

  

spawn

   spawn函数类似于execFile,默认不打开shell,但不同的是execFile缓存命令行的输出,然后将结果传入回调函数,spawn则以流的形式输出。有了流,连接输入和输出就非常方便了,比如典型的wc命令:

  const child=spawn(wc )

  process.stdin.pipe(child.stdin)

  child.stdout.on(data ,data={

  console.log(`子标准输出:\n${data} `)

  })此时,将从命令行stdin获得输入。当用户触发enter ctrl D时,命令将被执行,结果将从stdout输出。

  复杂的命令也可以通过管道组合,比如统计当前目录下的文件数,在Linux命令行中会这样写:

  找到。-type f wc -l的写法与Node.js中的命令行完全一样:

  const find=spawn(find ,[ . ,-type , f])

  const wc=spawn(wc ,[-l])

  find.stdout.pipe

  wc.stdout.on(data ,(data)={

  console.log(`文件数{ data } `)

  })spawn拥有丰富的自定义配置,例如:

  const child=spawn(find。-f类 wc -l ,{

  Stdio: inherit ,//继承父进程的iostream

  Shell: true,//打开命令行模式

  CWD:“/Users/keliq/code”,//指定执行目录

  Env: {ANSWER: 42 },//指定环境变量(默认为process.env)

  Detached: true,//作为独立进程存在

  })

fork

   fork函数是spawn函数的变种。用fork创建的子流程和父流程之间会自动创建一个通信通道,send方法会挂载到子流程的全局对象流程上。例如,父进程的parent.js代码:

  const { fork }=require( child _ process )

  const forked=fork(。/child . js’)

  forked.on(message ,msg={

  console.log(来自孩子的消息,msg);

  })

  forced.send ({hello: world})子进程的Child.js代码:

  process.on(message ,msg={

  console.log(来自父项的消息:,msg)

  })

  让计数器=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})

  }否则{

  res.end(确定)

  }

  })

  server . listen(3000);以下代码可用于模拟这一耗时的操作:

  const longComputation=()={

  设sum=0;

  for(设I=0;i 1e9i ) {

  总和=i

  }

  返回总和

  }然后上线后,只要服务器收到compute请求,由于Node.js是单线程的,耗时的操作占用了CPU,用户的其他请求都会在这里被阻塞,说明服务器没有响应。

  解决这个问题最简单的方法就是把耗时的操作放到一个子流程中,比如用下面的代码创建一个compute.js文件:

  const longComputation=()={

  设sum=0;

  for(设I=0;i 1e9i ) {

  sum=I;

  }

  返回总和

  }

  process.on(message ,msg={

  const sum=longComputation()

  process.send(总和)

  })然后稍微修改一下服务器的代码:

  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(开始)

  compute.on(message ,sum={

  res.end(总和为${sum})

  })

  }否则{

  res.end(确定)

  }

  })

  Server.listen(3000)这种情况下,主线程不会阻塞,而是继续处理其他请求,然后在返回耗时操作的结果时进行响应。实际上,更简单的处理方法是使用集群模块,由于篇幅限制,这将在后面讨论。

  

总结

  掌握了以上四种创建子流程的方法后,总结出以下三条规则:

  Fork用于创建节点子流程,因为它自己的通道便于通信。ExecFile或spawn用于创建非节点子进程。如果输出内容中很少使用execFile,那么结果会被缓存并发送到回调,方便处理;如果输出内容主要是spawn,那么使用stream不会占用很多内存。Exec用来执行复杂固定的终端命令,写起来更方便。但是一定要记住,exec会创建shell,效率不如execFile和spawn,存在命令行注入的风险。有关编程的更多信息,请访问:编程视频!以上是Node.js中创建子流程方法的详细分析请多关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: