node.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > node.js > Nodejs-child_process模块

Nodejs-child_process模块详细介绍

作者:一秋知叶

Node.js的child进程模块允许创建并行任务,提高应用性能,介绍了exec、execFile、spawn、fork等方法,解释了它们的使用场景和优势,通过子进程模块,可以执行外部命令、脚本或创建新的Node.js实例,感兴趣的朋友跟随小编一起看看吧

在 Node.js 应用程序中,child 进程模块非常重要,有了它可以实现并行处理,这在资源密集型任务里十分重要。

在本文中,我们将看一下 child 进程模块,解释其目的、使用方式以及如何使用。

什么是子进程模块

子进程是核心模块,允许用户创建和控制子进程。这些进程可以执行系统命令、运行各种语言的脚本,甚至可以创建新的 Node.js 实例。

child 进程模块的主要目的是允许同时执行多个进程,而不会阻塞主事件循环。

对于需要处理 CPU 密集型操作或执行外部命令和脚本的应用来说,使用 child 进程可以确保应用的高性能和响应性。

子进程的使用方式

child 进程可以用于以下任务:

创建子进程

要创建一个 child 进程,Node.js 为我们提供了四种主要方法来创建一个 child 进程,分别是 exec()execFile()spawn()fork()

exec() 方法

exec() 方法在 shell 中运行一个命令并缓冲输出。它适用于运行 shell 命令并记录输出。但由于是缓冲,它有内存限制。

下面是一个使用 exec() 方法执行命令并获取和处理一些系统信息的例子。

const { exec } = require("child_process");
exec("df -h", (error, stdout, stderr) => {
  if (error) {
    console.error(`exec error: ${error.message}`);
    return;
  }
  if (stderr) {
    console.error(`stderr: ${stderr}`);
    return;
  }
  const lines = stdout.trim().split("\n");
  const diskInfo = lines[1].split(/\s+/);
  const totalSpace = diskInfo[1];
  const usedSpace = diskInfo[2];
  const availableSpace = diskInfo[3];
  const usagePercent = diskInfo[4];
  console.log(`Total Space: ${totalSpace}`);
  console.log(`Used Space: ${usedSpace}`);
  console.log(`Available Space: ${availableSpace}`);
  console.log(`Usage: ${usagePercent}`);
});

这将执行 df -h 命令,解析其输出,并显示总的、已用的和可用的磁盘空间以及使用百分比。

运行代码时,您应该会看到类似这样的内容:

img

execFile() 方法

execFile() 方法在没有 shell 的情况下运行可执行文件。它比 exec() 更高效,因为它避免了 shell 的开销。

下面是一个如何使用 execFile() 方法的例子:

const { execFile } = require('child_process');
execFile("node", ["--version"], (error, stdout, stderr) => {
  if (error) {
    console.error(`execFile error: ${error.message}`);
    return;
  }
  if (stderr) {
    console.error(`stderr: ${stderr}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
});

这个例子展示了运行 Node.js 可执行文件来获取其版本。当命令不需要 shell 特性时,推荐使用 execFile()

spawn() 方法

与主要用于执行 shell 命令或可执行文件并捕获其输出的 exec 方法不同,spawn() 方法通过基于流的输出处理、直接与可执行文件交互、事件驱动的通信,提供了对 child 进程的更多控制。

spawn() 方法可用于需要直接交互的复杂场景。spawn() 启动一个新进程,给定一个命令,并提供流 i.e stdout, stderr 用于直接处理进程的输出和错误。

下面是一个如何使用 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() 运行 ls 命令并附加事件侦听器来处理进程的输出和退出状态。

运行代码时,您应该会看到类似这样的内容:

img

fork() 方法

fork() 方法可以说是为创建新的 Node.js 进程而设计的 spawn() 的变体。与可以启动任何类型进程的 spawn() 不同,fork() 方法针对创建本身是 Node.js 应用程序的 child 进程进行了优化。

它为 child 进程提供了一个额外的通信通道,允许在父进程和 child 进程之间进行简单的消息传输。

下面是一个如何使用 fork() 方法的例子。

父文件,即 parent.js

const { fork } = require("child_process");
const child = fork("child.js");
child.on("message", (message) => {
  console.log(`Message from child: ${message}`);
});
child.send("Hello, child process!");

child 进程文件,即 child.js

process.on("message", (message) => {
  console.log(`Message from parent: ${message}`);
  process.send("Hello from child process!");
});

在这里,fork() 创建了一个运行 child.js 脚本的新 Node.js 进程。它允许使用 send() 和 message 事件在父进程和子进程之间传递消息。

当您运行代码时,您应该会看到类似这样的内容:

img

fork() 与 spawn() 之间的区别

fork 和 spawn 之间的一些区别包括:

处理子进程输出

当创建一个 child 进程时,它会在两个主要流中产生输出:stdout 和 stderr。这些流保存了由 child 进程运行的命令或脚本的结果。要收集此输出,请为 child 进程对象添加事件侦听器,以在 stdout 和 stderr 上的 data 事件上。

Node.js 提供了几种特别有用的事件侦听器,用于处理 child 进程输出和错误。其中包括:

让我们看一个示例,展示如何生成一个 child 进程,捕获其输出,并处理可能发生的任何错误。

我们将使用 spawn() 方法来启动一个简单的命令(echo)并侦听输出和错误。

const { spawn } = require("child_process");
const child = spawn("echo", ["Hello, world"]);
child.stdout.on("data", (data) => {
  console.log(`stdout: ${data}`);
});
child.stderr.on("data", (data) => {
  console.error(`stderr: ${data}`);
});
child.on("error", (error) => {
  console.error(`Error occurred: ${error.message}`);
});
child.on("close", (code) => {
  console.log(`Child process exited with code $[code]`);
});

在这个例子中,父进程生成一个 child 进程来执行 echo 命令,该命令简单地将 Hello, world! 打印到终端。

父进程通过附加到 stdout 和 stderr 的 data 事件侦听器来捕获此输出。此外,它还侦听 error 事件以捕获在执行 child 进程期间可能发生的任何错误。

最后,close 事件指示 child 进程已完成执行,以及退出代码,这可以用来确定进程是否成功完成。

进程间通信

在分布式系统和并发编程中,进程间通信对于组件协调至关重要。Node.js 通过其 child 进程模块改进了这种通信。这使您能够创建 child 进程并促进进程间通信(IPC)。

这种 IPC 机制,特点是父进程和 child 进程之间交换数据,对于构建模块化和可扩展的应用程序至关重要。

有几种方法可以促进;一个突出的方法是通过 send() 方法和 message 事件进行消息传递。这种方法利用了 child 进程对象上可用的 send() 函数,向 child 进程发送消息,而 child 进程使用 message 事件侦听这些消息。

让我们用一个实际的例子来说明。我们将创建一个简单的应用程序,其中父进程分叉一个 child 进程,并使用 send() 方法和 message 事件与之通信。

父文件,即 parent.js,将如下所示:

const { fork } = require("child_process");
const child = fork("./child.js");
child.send({ greeting: "Hello from parent!" });
child.on("message", (msg) => {
  console.log("Message from child:", msg);
});
console.log("Waiting for response...");

child 进程文件,即 child.js

process.on("message", (msg) => {
  console.log("Message received from parent:", msg);
  process.send({ response: "Hello from child!" });
});

在这个例子中,父进程向 child 进程发送一条包含问候语的消息。child 进程侦听此消息,记录它,然后向父进程发送一条响应。父进程也侦听来自 child 进程的传入消息,并在收到时记录它们。

使用 send() 和 message 事件进行 IPC 的这种模式在需要协调父进程和 child 进程之间的操作时特别有用,例如共享数据、触发操作或在 Node.js 应用程序中实现请求-响应模式。

img

管理子进程的最佳实践

以下是一些用于有效管理 child 进程的最佳实践:

子进程与工作线程

虽然 child 进程对某些工作很有用,但 Node.js 还提供了另一种并行执行的方法。这种方法被称为工作线程,它与 child 进程完全不同。

worker threads 模块在 Node.js v10.50 中引入。与 child 进程相比,它提供了一种更有效的方式来处理多线程。下面是一个突出它们差异的表格

特性工作线程子进程
内存隔离与父进程共享内存空间每个子进程都有自己的内存堆(完全隔离)
通信使用消息传递,开销较小(通过 SharedArrayBuffer)通过 IPC 通道通信,开销较大
性能更轻量级,频繁数据交换的开销较低通信频繁时开销较高
用例平行计算,需要频繁数据交换的任务CPU 密集型任务,运行外部脚本,隔离任务
错误隔离错误可能影响主线程子进程中的错误不影响父进程
API 模块worker_threadschild_process
创建方法new Worker()spawn()fork()exec()execFile()
多线程真正的多线程,共享内存单独的进程,没有真正的多线程
开销由于共享内存而较低由于完全创建进程而较高
资源管理在同一进程内管理为每个进程分配单独的资源

何时使用子进程

当您需要完全隔离时,例如运行外部脚本或管理可能会使父进程崩溃的 CPU 密集型任务,可以使用 child 进程。

何时使用工作线程

另一方面,当任务从共享内存和频繁通信中受益时,可以使用 worker 线程,例如数据处理和并行计算。

结论

child 进程模块有助于执行并行任务,运行外部脚本和管理子进程。当您理解这些方法以及如何实现它们时,您将能够显著提高应用程序的性能和可扩展性。

到此这篇关于Nodejs-child_process模块解读的文章就介绍到这了,更多相关Nodejs-child_process模块内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文