• Nodejs进程间通信


    普通模式

    在 Node.js 里,通过 Child Process 模块 child_process.fork() 方法 fork 出来的子进程,提供了一个 chind.send 来进行进程间的消息通讯:

    const cp = require('child_process');
    const n = cp.fork(`${__dirname}/sub.js`);
     
    // 监听  message  事件来接收子进程发送的消息
    n.on('message', (m) => {
      console.log('PARENT got message:', m);
    });
     
    // 向子进程发送消息
    n.send({ hello: 'world' });
    // 监听 *message* 事件,接收来自父进程发送的消息
    process.on('message', (m) => {
      console.log('CHILD got message:', m);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    // 通过 process.send 向父进程发送消息
    process.send({ foo: ‘bar’ });
    实际上,通过 child_process.fork() 的方式 spawn 出来的子进程,默认激活了一个 IPC (进程间通信,Inter-Process Communication) 通道来进行通讯的。

    但是使用 fork 方法有一个很大的局限性,既只能用于产生 Node.js 子进程,如果调用的是其它语言(比如其它诸多世界上最好的各种语言)的时候,就跪了,同时在很多场景下,单一的 IPC 通道并不能满足需求(性能、流式处理等),这个时候,就只能祭出 child_proecess.spawn() 来处理了。

    进阶处理
    Node.js 一共提供了四种方式来产生子进程:

    • child_process.exec
    • child_process.execFile
    • child_process.fork
    • child_process.spawn

    实际上,前三种方法都是对 child_process.spawn 的特殊封装用于简化调用,那么既然 child_process.fork 能有方式激活 IPC 通道来进行进程间的通讯,直接 child_process.spawn 产生的子进程激活通讯通道也就不是什么问题了。

    调用 child_process.spawn 时,有三个参数需要处理:

    • command: 用来调用的命令
    • args:用来传递给 command 参数调用的命令的参数
    • options:一组产生子进程时的配置参数
      我们需要的东西,就在 options.stdio 里。

    options.stdio 用于配置建立父进程与子进程之间的通讯管道,他的值可以是一个数组或者字符串,当为数组时,每个索引对应子进程中的一个文件标识符,默认情况下,Node.js 会为其 spawn 的子进程打开三个文件标识符,既子进程的 stdin 、stdoutstderr 流会被重定向到 * ChildProcess* 对象的 child.stdin, child.stdout 和 child.stderr 上,而当 options.stdio 的值为字符串时,对应下面的三种情况:

    • ‘pipe’:等价于 [‘pipe’, ‘pipe’, ‘pipe’] (默认情况)
    • ‘ignore’:等价于 [‘ignore’, ‘ignore’, ‘ignore’]
    • ‘inherit’:等价于 [process.stdin, process.stdout, process.stderr] 或者 [0,1,2]

    在实际使用中,我们可以根据需要调整 options.stdio 的配置,比如忽略 stdin 和 stdout,并把 child 的 stderr 重定向到 process.stderr:

    // parent.js
    'use strict';
     
    const child_process = require('child_process');
    let worker = child_process.spawn('node', ['child.js'], {
        stdio: ['ignore', 'ignore', process.stderr]
    });
     
    // child.js
    'use strict';
     
    console.log('Hello world!');
    console.error('Hello error!');  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    此时执行 parent.js,仅会输出 Hello error!,因为我们配置忽略了 stdout 的输出。通过这三个值的灵活配置,我们可以实现多种样式的数据输入、输出。

    高阶模式

    默认情况下, child_process 在 spawn 的时候,只打开了三个文件标识符,而实际上,这个数量是可以继续扩展的,同时用于通讯的除了上面提到的 pipe 和 IPC,还可以直接使用 Stream,所以,你是不是已经想到了一些美妙的事情了:)

    下面我们来扩展一下上面的例子,添加一条额外的 Stream 用于从 child 向 parent 发送数据。

    // parent.js
    'use strict';
     
    const child_process = require('child_process');
     
    let worker = child_process.spawn('node', ['child.js'], {
        stdio: ['ignore', 'ignore', process.stderr, 'pipe']
    });
     
    // 监听创建的 Stream
    worker.stdio[3].on('data', (chunk) => {
        console.log(chunk.toString());
    });
     
     
    // child.js
    'use strict';
     
    const fs = require('fs');
     
    let ws = fs.createWriteStream(null, {
        fd: 3
    });
     
    let doit = () => {
        ws.write(`Hello world! ${Date.now()}`, () => {
            setTimeout(doit, 1000);
        });
    };
     
    doit();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    上面的实例中,因为我们明确知道当前打开的第四个文件标识符(索引从0开始)是我们在父进程中通过 ‘pipe’ 参数指定的,因此我们可以使用 fs.createWriteStream 的高阶用法,通过指定 fd 来创建一个 WriteStream。

    使用同样的方式,可以继续扩充添加 stream 用于数据交换,从而实现进程间高效的数据交互。

    实际上,这种进程间通讯的方式在各种语言中都是通用的,比如在之前阿里云的消息队列没有提供 Node SDK的情况下,因为业务需要,跟当时的小伙伴一起,利用这种方式,spawn 了一个PHP的子进程来调用阿里云的消息队列并进行数据交互,比较低成本的解决了一个很急业务需求。

  • 相关阅读:
    机器学习(三十六):随机梯度下降(SGD)算法
    抗CD4单抗偶联表阿霉素/单克隆抗体Zh805/特异性靶向肽A54偶联阿霉素的制备
    [html]当网站搭建、维护的时候,你会放个什么界面?
    php在线审稿系统mysql数据库web结构layUI布局apache计算机软件工程网页wamp
    【Linux】基础开发工具——make/Makefile+进度条小程序
    1. Vue3新特性 —— Vue3深入学习
    HTML+CSS期末大作业 中国传统美食网站设计 节日美食13页 html5网页设计作业代码 html制作网页案例代码 html大作业网页代码
    Thymeleaf中使用二维数组[[]]报错:Could not parse as expression
    Java8新特性—四大内置函数式接口
    软件测试学习笔记丨Selenium复用已打开浏览器
  • 原文地址:https://blog.csdn.net/jgku/article/details/128176838