前端面试题 - 31. node进程间如何通信?

1,070 阅读3分钟

通信方式

Node.js 进程间可以通过以下几种方式进行通信:

  1. 子进程与父进程间的通信:可以使用 child_process 模块中的 send() 方法和 on("message") 事件来实现。父进程可以通过 child_process.fork() 方法启动一个子进程,并且使用 send() 方法来向子进程发送消息,子进程可以通过 process.on("message") 事件来监听父进程发送的消息。
  2. 父进程与子进程间的通信:与上面的方式相反,可以使用 process.send() 方法和 on("message") 事件来实现。这种方式通常用于父进程与子进程之间的协作,比如启动子进程处理一些耗时的任务,然后将处理结果发送回父进程。
  3. 进程间共享内存:可以使用 Buffer 对象、SharedArrayBuffer 对象、TypedArray 对象等方式在不同的进程间共享内存。这种方式通常用于需要高效地共享数据的场景,比如多个进程同时处理大量数据的情况。
  4. 进程间信号量通信:可以使用 process.kill() 方法向另一个进程发送信号,比如 SIGUSR1SIGUSR2 信号。这种方式通常用于进程间的控制和协作,比如向另一个进程发送停止信号、重启信号等。 总之,Node.js 进程间可以通过不同的方式进行通信,可以根据具体的需求选择适合的方式。在实际应用中,通常会结合多种方式来实现进程间的协作和通信。

示例1: 父子进程间通信

父进程代码:

javascriptCopy code
const { fork } = require("child_process");
// 启动子进程
const child = fork("./child.js");
// 监听子进程发送的消息
child.on("message", (msg) => {
  console.log(`Received message from child process: ${msg}`);
});
// 向子进程发送消息
child.send("Hello from parent process!");

子进程代码:

javascriptCopy code
// 监听父进程发送的消息
process.on("message", (msg) => {
  console.log(`Received message from parent process: ${msg}`);
  // 向父进程发送消息
  process.send("Hello from child process!");
});

在上面的例子中,父进程通过 fork() 方法启动了一个子进程,并且监听了子进程发送的消息。子进程则通过 process.on("message") 方法监听父进程发送的消息,并且在接收到消息后向父进程发送了一个回复消息。通过这种方式,父进程和子进程之间就可以进行通信了。

示例2: 进程间共享内存来通信

const { Worker, isMainThread, workerData } = require("worker_threads");
if (isMainThread) {
  // 主线程创建共享内存
  const buffer = new SharedArrayBuffer(4);
  // 创建子线程,并传入共享内存
  const worker = new Worker(__filename, { workerData: buffer });
  // 监听子线程发送的消息
  worker.on("message", (msg) => {
    console.log(`Received message from worker thread: ${msg}`);
    console.log(`SharedArrayBuffer value is: ${new Int32Array(buffer)[0]}`);
  });
  // 向子线程发送消息,并修改共享内存中的值
  new Int32Array(buffer)[0] = 42;
  worker.postMessage("Hello from main thread!");
} else {
  // 子线程读取共享内存,并向主线程发送消息
  const buffer = workerData;
  console.log(`SharedArrayBuffer value is: ${new Int32Array(buffer)[0]}`);
  process.on("message", (msg) => {
    console.log(`Received message from main thread: ${msg}`);
    new Int32Array(buffer)[0] = 100;
    // 向主线程发送消息,并修改共享内存中的值
    process.send("Hello from worker thread!");
  });
}

在上面的例子中,主线程创建了一个 SharedArrayBuffer 对象,并将其传递给子线程。主线程修改了共享内存中的值,并向子线程发送了一个消息。子线程读取共享内存中的值,并向主线程发送了一个回复消息,并修改了共享内存中的值。通过这种方式,主线程和子线程之间就可以共享内存并进行通信了。

示例3:进程间信号量通信

const { spawn } = require("child_process");
// 启动子进程
const child = spawn("node", ["child.js"]);
// 监听子进程的 stdout 输出
child.stdout.on("data", (data) => {
  console.log(`Received message from child process: ${data}`);
});
// 向子进程发送 SIGUSR1 信号
child.kill("SIGUSR1");

子进程代码(child.js):

// 监听 SIGUSR1 信号
process.on("SIGUSR1", () => {
  console.log("Received signal from parent process!");
  // 向父进程发送消息
  process.stdout.write("Hello from child process!");
});

在上面的例子中,父进程通过 spawn() 方法启动了一个子进程,并且监听子进程的 stdout 输出。父进程向子进程发送了一个 SIGUSR1 信号,子进程收到信号后向父进程发送了一条消息,并输出到 stdout。通过这种方式,父进程和子进程之间就可以使用进程间信号量进行通信了。