在上一讲中,我们提到过,凡是面试官问“什么情况下”的时候,面试官实际想听的是你经过理解,整理得到的认知。回答应该是概括的、简要的。而不是真的去列举每一种 case。

另外,面试官考察进程间通信,有一个非常重要的意义——进程间通信是架构复杂系统的基石。复杂系统往往是分成各种子系统、子模块、微服务等等,按照 Unix 的设计哲学,系统的每个部分应该是稳定、独立、简单有效,而且强大的。系统本身各个模块就像人的器官,可以协同工作。而这个协同的枢纽,就是我们今天的主题——进程间通信。

什么是进程间通信?

  • 进程间通信(Intermediate Process Communication,IPC)。所谓通信就是交换数据。
  • 所以,狭义地说,就是操作系统创建的进程们之间在交换数据。
  • 我们今天不仅讨论狭义的通信,还要讨论 IPC 更广泛的意义——程序间的通信。
  • 程序可以是进程,可以是线程,可以是一个进程的两个部分(进程自己发送给自己),也可以是分布式的——总之,今天讨论的是广义的交换数据。

管道

  • 之前我们在“07 | 进程、重定向和管道指令:xargs 指令的作用是?”中讲解过管道和命名管道。
  • 管道提供了一种非常重要的能力,就是组织计算。
  • 进程不用知道有管道存在,因此管道的设计是非侵入的。
  • 程序员可以先着重在程序本身的设计,只需要预留响应管道的接口,就可以利用管道的能力。
  • 比如用shell执行MySQL语句,可能会这样:
  • 进程1 | 进程2 | 进程3 | mysql -u... -p | 爬虫进程
    

    我们可以由进程 1、进程 2、进程 3 计算出 MySQL 需要的语句,然后直接通过管道执行。MySQL经过计算将结果传给一个爬虫进程,爬虫就开始工作。MySQL并不是设计用于管道,爬虫进程也不是设计专门用于管道,只是程序员恰巧发现可以这样用,完美地解决了自己的问题,比如:用管道构建一个微型爬虫然后把结果入库。

我们还学过一个词叫作命名管道。命名管道并没有改变管道的用法。相比匿名管道,命名管道提供了更多的编程手段。比如:

  • 上面的程序将两个进程的临时结果都同时重定向到 namedpipe,相当于把内容合并了再找机会处理。
  • 再比如说,你的进程要不断查询本地的 MySQL,也可以考虑用命名管道将查询传递给 MySQL,再用另一个命名管道传递回来。
  • 这样可以省去和 localhost 建立 TCP 3 次握手的时间。 当然,现在数据库都是远程的了,这里只是一个例子。
  • 管道的核心是不侵入、灵活,不会增加程序设计负担,又能组织复杂的计算过程

本地内存共享

  • 同一个进程的多个线程本身是共享进程内存的。 这种情况不需要特别考虑共享内存。
  • 如果是跨进程的线程(或者理解为跨进程的程序),可以考虑使用共享内存。
  • 内存共享是现代操作系统提供的能力, Unix 系操作系统,包括 Linux 中有 POSIX 内存共享库——shmem。
  • Linux 内存共享库的实现原理是以虚拟文件系统的形式,从内存中划分出一块区域,供两个进程共同使用。看上去是文件,实际操作是内存。
  • 共享内存的方式,速度很快,但是程序不是很好写,因为这是一种侵入式的开发,也就是说你需要为此撰写大量的程序。
  • 比如如果修改共享内存中的值,需要调用 API。如果考虑并发控制,还要处理同步问题等。
  • 因此,只要不是高性能场景,进程间通信通常不考虑共享内存的方式。

本地消息/队列

  • 内存共享不太好用,因此本地消息有两种常见的方法。一种是用消息队列——现代操作系统都会提供类似的能力。Unix 系可以使用 POSIX 标准的 mqueue。另一种方式,就是直接用网络请求,比如 TCP/IP 协议,也包括建立在这之上的更多的通信协议(这些我们在下文中的“远程调用”部分详细讲解)。
  • 本质上,这些都是收/发消息的模式。进程将需要传递的数据封装成格式确定的消息,这对写程序非常有帮助。程序员可以根据消息类型,分门别类响应消息;也可以根据消息内容,触发特殊的逻辑操作。在消息体量庞大的情况下,也可以构造生产者队列和消费者队列,用并发技术进行处理。

远程调用

  • 远程调用(Remote Procedure Call,RPC)是一种通过本地程序调用来封装远程服务请求的方法。
  • 程序员调用 RPC 的时候,程序看上去是在调用一个本地的方法,或者执行一个本地的任务,但是后面会有一个服务程序(通常称为 stub),将这种本地调用转换成远程网络请求。
  • 同理,服务端接到请求后,也会有一个服务端程序(stub),将请求转换为一个真实的服务端方法调用。

你可以观察上面这张图,表示客户端和服务端通信的过程,一共是 10 个步骤,分别是:

  1. 客户端调用函数(方法);

  2. stub 将函数调用封装为请求;

  3. 客户端 socket 发送请求,服务端 socket 接收请求;

  4. 服务端 stub 处理请求,将请求还原为函数调用;

  5. 执行服务端方法;

  6. 返回结果传给 stub;

  7. stub 将返回结果封装为返回数据;

  8. 服务端 socket 发送返回数据,客户端 socket 接收返回数据;

  9. 客户端 socket 将数据传递给客户端 stub;

  10. 客户端 stub 把返回数据转义成函数返回值。

  • RPC 调用过程有很多约定, 比如函数参数格式、返回结果格式、异常如何处理。
  • 还有很多细粒度的问题,比如处理 TCP 粘包、处理网络异常、I/O 模式选型
  • 上面这些问题比较棘手,因此在实战中通常的做法是使用框架。比如 Thrift 框架(Facebook 开源)、Dubbo 框架(阿里开源)、grpc(Google 开源)。
  • 这些 RPC 框架通常支持多种语言,这需要一个接口定义语言支持在多个语言间定义接口(IDL)。
  • RPC 调用的方式比较适合微服务环境的开发,当然 RPC 通常需要专业团队的框架以支持高并发、低延迟的场景。
  • 不过,硬要说 RPC 有额外转化数据的开销(主要是序列化),也没错,但这不是 RPC 的主要缺点。
  • RPC 真正的缺陷是增加了系统间的耦合当系统主动调用另一个系统的方法时就意味着在增加两个系统的耦合
  • 长期增加 RPC 调用会让系统的边界逐渐腐化。这才是使用 RPC 时真正需要注意的东西。

消息队列

  • 既然 RPC 会增加耦合,那么怎么办呢——可以考虑事件
  • 事件不会增加耦合,如果一个系统订阅了另一个系统的事件,那么将来无论谁提供同类型的事件,自己都可以正常工作。
  • 系统依赖的不是另一个系统,而是某种事件。
  • 如果哪天另一个系统不存在了,只要事件由其他系统提供,系统仍然可以正常运转。
  • 实现事件可以用消息队列
  • 另一个用到消息队列的场景是纯粹大量数据的传输。 比如日志的传输,中间可能还会有收集、清洗、筛选、监控的节点,这就构成了一个庞大的分布式计算网络。
  • 总的来说,消息队列是一种耦合度更低,更加灵活的模型。
  • 但是对系统设计者的要求也会更高,对系统本身的架构也会有一定的要求。具体场景的消息队列有 Kafka,主打处理 feed;RabbitMQ、ActiveMQ、 RocketMQ 等主打分布式应用间通信(应用解耦)。

总结: 进程间通信都有哪些方法?

可以从单机和分布式角度给面试管阐述

  • 如果考虑单机模型,有管道、内存共享、消息队列。这三个模型中,内存共享程序最难写,但是性能最高。管道程序最好写,有标准接口。消息队列程序也比较好写,比如用发布/订阅模式实现具体的程序。
  • 如果考虑分布式模型,就有远程调用、消息队列和网络请求。直接发送网络请求程序不好写,不如直接用实现好的 RPC 调用框架。RPC 框架会增加系统的耦合,可以考虑 消息队列,以及发布订阅事件的模式,这样可以减少系统间的耦合。

进程间通信: 进程间通信都有哪些方法?相关推荐

  1. Effective Java:对于全部对象都通用的方法

    前言: 读这本书第1条规则的时候就感觉到这是一本非常好的书.可以把我们的Java功底提升一个档次,我还是比較推荐的.这里我主要就关于覆盖equals.hashCode和toString方法来做一个笔记 ...

  2. 如何做好网络推广中有关网站优化中内链搭建都有什么方法?

    在网站优化的过程中,如何做好网络推广中不同的优化人员对于优化技巧的使用和优化重点也会有所不同,但其中,内链的优化也是不容忽视的一点,它就相当于网站的内部循环系统,做好它才能让网站更好地运行,那么对于网 ...

  3. Effective Java:对于所有对象都通用的方法

    前言: 读这本书第1条规则的时候就感觉到这是一本很好的书,可以把我们的Java功底提升一个档次,我还是比较推荐的.这里我主要就关于覆盖equals.hashCode和toString方法来做一个笔记总 ...

  4. [react] 在React中我们怎么做静态类型检测?都有哪些方法可以做到?

    [react] 在React中我们怎么做静态类型检测?都有哪些方法可以做到? flow 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持一定很酷.欢迎大家一起讨论 主目录 与歌谣 ...

  5. [html]html实现页面跳转都有哪些方法?

    [html]html实现页面跳转都有哪些方法? 创建A标签跳转location.hrefform submit<meta http-equiv="refresh" conte ...

  6. [js] js源代码压缩都有哪些方法?它们的压缩原理分别是什么

    [js] js源代码压缩都有哪些方法?它们的压缩原理分别是什么 方法 1.在线工具 2.webpack原理 1.删除注释 2.变量名方法名字符精减 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放 ...

  7. java继承实现不用每个类都写toString方法

    每个类都写toString方法很麻烦,采用继承可以很好的解决 import java.io.Serializable;import org.apache.commons.lang.builder.To ...

  8. 微信消息能在服务器上彻底清除,快速彻底删除微信消息的方法如此简单 很多人都用错了方法!...

    原标题:快速彻底删除微信消息的方法如此简单 很多人都用错了方法! 我们每天都要用微信接收消息,不管是群里发送的还是个人的回复的,大量的信息接踵而至,使得微信内的消息过多致使微信内存不够用,出现微信功能 ...

  9. react想要子组件每次显示的时候都执行componentDidMount方法

    1.把子组件的显示用一个state的值去控制,每次state变化的时候都会导致子组件的重新渲染,componentDidMount方法自然每次都会执行 2.给子组件设置一个随机的key值,每次显示的时 ...

最新文章

  1. 关闭Windows 2000/XP/2003默认共享
  2. Linux系统适配苹果M1 芯片的项目有新进展
  3. python读取excel表格-Python读取Excel单元格的内容
  4. CPU访问计算机各组件周期
  5. Mysql 8 逻辑升级详解
  6. 利用jqueryRotare实现抽奖转盘
  7. Codeforces Round #703 (Div. 2) Guessing the Greatest C1 C2 二分
  8. 滨河新区(黄河楼)夜景
  9. 微信小程序---实现弹窗效果
  10. mybatis plus骚操作之逻辑删除
  11. CentOS7 防火墙关闭
  12. BLOB:大数据,大对象,在数据库中用来存储超长文本的数据,例如图片等
  13. 由一次NoHttpResponseException异常,追究到Http长连接和短连接
  14. 联想重装系统去掉保护_带有联想保护系统的电脑安装系统具体步骤如下
  15. 航空系统c语言课程设计报告,c语言课程设计报告_航空订票系统西安郵電學院.doc...
  16. 2022年下半年软考考哪个科目?看完就懂了
  17. vue2支付宝网页授权登录
  18. 2022年危险化学品经营单位安全管理人员考试模拟100题及模拟考试
  19. 一文搞懂 | Linux 同步管理(上)
  20. 职业生涯规划需要考虑的三大要点

热门文章

  1. Mysql数据库快速插入亿级数据
  2. 一个月提升口语听力n个level
  3. Object.assign的原理及其实现方式
  4. python入门实例
  5. APEX包管理器简述(二)
  6. 语音特征MFCC和PLP
  7. java关闭事件_为Java程序添加退出事件
  8. 怎样使用计算机函数求出等级,巧用Excel函数出练习题
  9. mysql查询学科_查询出各个学科的前3名的同学信息的Sql
  10. 学android开发 不得不去的好地方