Node产生的子进程何时真正开始?

卡兹

Node的Child Processspawn()函数文档中,以及在其他地方看到的示例中,模式是调用spawn()函数,然后在返回的ChildProcess对象上设置一堆处理程序例如,这是该spawn()文档页面给出的第一个示例

const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

spawn()函数本身在第二行上调用。我的理解是spawn()异步启动子进程。从文档中:

child_process.spawn()方法使用给定命令在args中带有命令行参数来生成新进程。

但是,上面脚本的以下几行继续为该进程设置各种处理程序,因此假设该进程spawn()在第2行被调用的时间之间并未真正启动(并可能完成),而其他事情发生在随后的行。我知道JavaScript / Node是单线程的。但是,操作系统不是单线程的,天真的会读到该spawn()调用,告诉操作系统立即生成进程(此时,不幸的是,操作系统可能会挂起父Node进程并运行/完成。在执行下一行Node代码之前的子进程)。

但是必须确保在当前JavaScript函数完成之前(或更一般而言,调用当前函数的当前JavaScript事件处理程序完成),实际上不会产生该过程,对吗?

这似乎是一件非常重要的事情。为什么在“子进程”文档页面中没有这么说?是否有一些压倒一切的Node原理,使得不必明确地说出来?

jfriend00

新进程的产生立即开始(已移交给操作系统以实际启动该进程并使之继续运行)。使用.spawn()异步和非阻塞启动新进程因此,它将启动操作系统的操作并立即返回。您可能认为这就是为什么可以在事件返回后设置事件处理程序的原因(因为该过程尚未完成启动)。好吧,是的,不是。它可能尚未完成新过程的启动,但这不是行之有效的主要原因。

可以,因为node.js通过一个线程事件队列运行所有事件。因此,直到代码完成执行并将控制权返回给系统后,才能处理新产生的进程中的事件。只有这样,它才能处理事件队列中的下一个事件并触发要为其注册处理程序的事件之一。

或者,换句话说,来自另一个进程的事件都不是先发制人的。他们不会/不能中断您现有的Javascript代码。因此,由于您仍在运行Javascript代码,因此这些事件尚未运行。而是将它们放在事件队列中,直到您的Javascript代码完成,然后解释器才能从事件队列中获取下一个事件并运行与其关联的回调。同样,该回调将一直运行,直到返回到解释器,然后解释器才能获取下一个事件并运行其回调,依此类推...

这就是为什么node.js被称为事件驱动系统的原因。

这样,执行这种类型的结构就可以了:

const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

在完成代码并将控制权返回给系统之前,这些事件dataclose事件均无法执行其回调。因此,像您一样设置这些事件处理程序是绝对安全的。即使新生成的进程正在运行并立即生成事件,这些事件也将一直位于事件队列中,直到您的Javascript完成其工作(包括设置事件处理程序)为止。

现在,如果您将事件处理程序的设置延迟到事件循环(如下面所示)的某个将来的滴答声(如下所示)setTimeout(),那么您可能会错过一些事件:

const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);

setTimeout(() => {    
    ls.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`);
    });

    ls.stderr.on('data', (data) => {
      console.error(`stderr: ${data}`);
    });

    ls.on('close', (code) => {
      console.log(`child process exited with code ${code}`);
    });
}, 10);

在这里,您并不是在事件循环的同一滴答中立即设置事件处理程序,而是经过短暂的延迟。因此,在安装事件处理程序之前,可以从事件循环中处理一些事件,并且您可能会错过其中一些事件。显然,您永远不会这样做(故意),但我只是想证明在事件循环的同一时间运行的代码没有问题,但是在事件循环的未来时间运行的代码可能有问题。缺少事件的问题。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

cronjob何时真正开始?

来自分类Dev

Jersey Rest服务何时真正开始/关闭?

来自分类Dev

如何使Notepad ++真正开始最大化?

来自分类Dev

如何杀死由kill或kill -9脚本开始的进程产生的所有子进程

来自分类Dev

Python何时创建子进程?

来自分类Dev

Python何时创建子进程?

来自分类Dev

Python子进程:知道命令何时完成

来自分类Dev

仅在完成子进程后才开始/继续父进程

来自分类Dev

何时真正调用idTokenChanges?

来自分类Dev

bash子外壳会产生新的bash进程吗?

来自分类Dev

在Electron中产生一个子进程

来自分类Dev

当期望数字列表时,Python子进程communication()产生None

来自分类Dev

如何并行产生五个子进程

来自分类Dev

计算命令产生的子进程总数(递归)

来自分类Dev

bash子外壳会产生新的bash进程吗?

来自分类Dev

计算命令产生的子进程总数(递归)

来自分类Dev

包含子进程的回声会产生意外的输出

来自分类Dev

开始后分离一个生成子进程

来自分类Dev

node.js中产生的进程立即退出

来自分类Dev

Scala何时真正复制对象?

来自分类Dev

libjit何时真正值得?

来自分类Dev

VirtualBox快照何时真正发生

来自分类Dev

Scala何时真正复制对象?

来自分类Dev

POSIX select()何时真正返回?

来自分类Dev

node.js 与 docker 中的子进程

来自分类Dev

node.js子进程更改目录并运行该进程

来自分类Dev

如何从Node JS中的子进程获取进程ID

来自分类Dev

Node.js 子进程到 Python 进程

来自分类Dev

流程何时开始