深入了解Node.js和Electron是如何做进程通信的


当前第2页 返回上一页

还有如果是想执行 js ,那就用 fork:

1

2

3

4

5

6

7

const { fork } = require('child_process'); 

 

const xxxProcess = fork('./xxx.js');   

xxxProcess.send('111111'); 

xxxProcess.on('message', sum => {   

    res.end('22222');  

});

小结

简单小结一下 child_process 的 4 个 api:

如果想执行 shell 命令,用 spawn 和 exec,spawn 返回一个 stream,而 exec 进一步封装成了 buffer。除了 exec 有的时候需要设置下 maxBuffer,其他没区别。

如果想执行可执行文件,用 execFile。

如果想执行 js 文件,用 fork。

child_process 的进程通信

说完了 api 我们来说下 child_process 创建的子进程怎么和父进程通信,也就是怎么做 ipc。

pipe

首先,支持了 pipe,很明显是通过管道的机制封装出来的,能同步的传输流的数据。

1

2

3

4

const { spawn } = require('child_process');

 

const find = spawn('cat', ['./aaa.js']);

const wc = spawn('wc', ['-l']);  find.stdout.pipe(wc.stdin);

比如上面通过管道把一个进程的输出流传输到了另一个进程的输入流,和下面的 shell 命令效果一样:

1

cat ./aaa.js | wc -l

message

spawn 支持 stdio 参数,可以设置和父进程的 stdin、stdout、stderr 的关系,比如指定 pipe 或者 null。还有第四个参数,可以设置 ipc,这时候就是通过事件的方式传递消息了,很明显,是基于消息队列实现的。

1

2

3

4

5

6

7

8

9

const { spawn } = require('child_process');

 

const child = spawn('node', ['./child.js'], {

    stdio: ['pipe', 'pipe', 'pipe', 'ipc']

});

child.on('message', (m) => {

    console.log(m);

});

child.send('xxxx');

而 fork 的 api 创建的子进程自带了 ipc 的传递消息机制,可以直接用。

1

2

3

4

5

6

7

const { fork } = require('child_process'); 

 

const xxxProcess = fork('./xxx.js');   

xxxProcess.send('111111'); 

xxxProcess.on('message', sum => {   

    res.end('22222');  

});

cluster

cluster 不再是父子进程了,而是更多进程,也提供了 fork 的 api。

比如 http server 会根据 cpu 数启动多个进程来处理请求。

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

import cluster from 'cluster';

import http from 'http';

import { cpus } from 'os';

import process from 'process';

 

const numCPUs = cpus().length;

 

if (cluster.isPrimary) {

  for (let i = 0; i < numCPUs; i++) {

    cluster.fork();

  }

} else {

  const server = http.createServer((req, res) => {

    res.writeHead(200);

    res.end('hello world\n');

  })

   

  server.listen(8000);

   

  process.on('message', (msg) => {

    if (msg === 'shutdown') {

       server.close();

    }

  });

}

它同样支持了事件形式的 api,用于多个进程之间的消息传递,因为多个进程其实也只是多个父子进程的通信,子进程之间不能直接通信,所以还是基于消息队列实现的。

共享内存

子进程之间通信还得通过父进程中转一次,要多次读写消息队列,效率太低了,就不能直接共享内存么?

现在 nodejs 还是不支持的,可以通过第三方的包 shm-typed-array 来实现,感兴趣可以看一下。

https://www.npmjs.com/package/shm-typed-array

总结

进程包括代码、数据和 PCB,是程序的一次执行的过程,PCB 记录着各种执行过程中的信息,比如分配的资源、执行到的地址、用于通信的数据结构等。

进程之间需要通信,可以通过信号量、管道、消息队列、共享内存的方式。

  • 信号量就是一个简单的数字的标记,不能传递具体数据。

  • 管道是基于文件的思想,一个进程写另一个进程读,是同步的,适用于两个进程。

  • 消息队列有一定的 buffer,可以异步处理消息,适用于两个进程。

  • 共享内存是多个进程直接操作同一段内存,适用于多个进程,但是需要控制访问顺序。

这四种是本地进程的通信方式,而网络进程则基于网络协议的方式也可以做进程通信。

进程通信叫做 ipc,本地的叫做 lpc,远程的叫 rpc。

其中,如果把消息再封装一层成具体的方法调用,叫做 rmi,效果就像在本进程执行执行另一个进程的方法一样。

electron 和 nodejs 都是基于上面的操作系统机制的封装:

  • elctron 支持 ipcMain 和 ipcRenderer 的消息传递的方式,还支持了 remote 的 rmi 的方式。

  • nodejs 有 child_process 和 cluster 两个模块和进程有关,child_process 是父子进程之间,cluster 是多个进程:

    • child_process 提供了用于执行 shell 命令的 spawn、exec,用于执行可执行文件的 execFile,用于执行 js 的 fork。提供了 pipe 和 message 两种 ipc 方式。

    • cluster 也提供了 fork,提供了 message 的方式的通信。

当然,不管封装形式是什么,都离不开操作系统提供的信号量、管道、消息队列、共享内存这四种机制。

ipc 是开发中频繁遇到的需求,希望这篇文章能够帮大家梳理清楚从操作系统层到不同语言和运行时的封装层次的脉络。

原文地址:https://juejin.cn/post/6988484297485189127

作者:zxg_神说要有光

更多编程相关知识,请访问:编程视频!!

以上就是深入了解Node.js和Electron是如何做进程通信的的详细内容,更多文章请关注木庄网络博客

返回前面的内容

相关阅读 >>

了解一下node.js中的文件夹写入

node.js底层是什么语言

node.js爬取豆瓣数据实例

express4.x中间件特性的介绍(代码示例)

深入浅析with的使用

node.js进行调试的几种方法介绍

详解node.js中的事件

nw.js是什么?

electron ipcmain 模块

electron 离屏渲染

更多相关阅读请进入《node.js》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...