前言
某个不眠之夜,你的安卓手机响了。
拿起手机一看,原来是家人/朋友/老板等给你一条微信。
你想了一会,决定查看这条信息。
你解锁了手机,点开消息通知,看到显示的文字后,你沉思了几秒钟/分钟。
过了一会,你想好了要回复的文字。
你点击文本输入框,在弹出的输入法键盘敲打,形成了要发送的文字片段,然后点击“发送”按钮。
过一会,你的联系人会收到你发的文字。
这一切的背后,究竟有什么黑科技?让我们来走进科学(大误)
简要介绍
现代计算机(包括日常用的智能手机),每个应用至少占用一个进程(有些大型应用,如微信Android App等,占用不止一个进程)。
刚刚的例子中,安卓系统在A进程,微信在B进程,输入法在C进程。
问题来了,通过输入法键盘输入的文字,是怎样到微信的文本输入框呢?
微信和输入法在不同进程。输入法收到的点击按键事件,通过进程间通信,先传递到系统进程,系统进程通过Android Handler模块,将按键事件分发出去,微信App收到这些事件后,将事件取出,显示在文本输入框里。
在这过程中,消息队列发挥着重要作用。
消息队列是什么呢?
下面给出了队列的简要介绍
- 一种进程间通信方式
- 主要由四部分组成
- 生产者 -- 发消息的一方
- 消费者 -- 收消息的一方
- 队列 -- 提供消息存储能力,可起到缓存作用
- 消息 -- 携带所需信息的对象
我们先从常见的Android手机应用和网页应用说起
Android方面的应用
典型例子是Android的Handler机制,使用单线消息队列模型,也是有四部分组成。
- 生产者 -- Handler A,可通过sendMessage(),post()来发送消息,支持延时
- 消费者 -- Handler B,通过重写handleMessage()方法来处理消息
- 队列 -- MessageQueue、Looper,用于缓存信息和保证消息按序执行
- 消息 -- Message,如输入事件,绘制图形事件等,也支持自定义的事件
这样设计有以下好处
- 开发者可方便切换代码执行的线程
- 按顺序规则地处理消息,避免并发
- 阻塞线程,避免让线程结束
- 延迟处理消息
对于系统层面,可避免大量的回调代码,降低维护成本。
刚刚的例子中,正是Handler机制,把输入法收到的点击按键事件,传递到微信的文本输入框。
在点击“发送”按钮后,微信App通过Handler机制,将发送消息后得到的结果,显示到面前,你才知道这消息的发送结果。
网页开发的应用
典型例子是Javascript引擎V8(由Google开发)。
我们日常见到的页面,都是UI线程(也称为主线程)绘制。
除了绘制和更新界面,UI线程还有接收屏幕移动、点击、输入事件的作用。
每次网络请求(包括但不限于查询、提交等)都是耗时操作,耗时操作都会阻塞线程。为了不让主线程被堵塞,网络请求都需在另一个线程(也称为子线程)执行。
为了能让使用者知道网络请求的结果(显示对应的成功页面,或者是错误页面),需要将子线程的结果通知主线程,主线程根据子线程的结果更新页面。
为了让消息(点击事件,页面刷新等事件)有序执行,V8引擎也采用消息队列来处理信息。
通过鼠标、键盘、触控板等产生的消息都会被添加进消息队列,主线程会循环地从消息队列中取出消息并执行。
Android Handler也是这样的运行机制。
说完常见的安卓手机应用和网页应用,再说说后端应用。
为什么要说后端应用?因为后端应用的主要作用,是为这些前端应用提供数据的。
后端开发的应用
每个组织的业务需求不一样,所带来的技术需求也不一样。
为满足不同的技术需求,有不同的消息队列的框架,以用于后端开发,例如Kafka、rabbitMQ、rocketMQ等。
这些框架模型一样,实现侧重点不同,有各自适用的场景。
当你参与秒杀某某商品时,这些消息队列框架,能确保千千万万个用户的购买、支付请求不会丢失,保证都被处理到。
后记
有些人说,新技术那么多,学不动了。
但通过上面的分析,软件框架有很多相通之处,只要我们能掌握本质的思维模型,还是能学得动的。
参考资料
Kafka:如何分析一个软件的实现? -- 软件设计之美 time.geekbang.org/column/arti…
Android由浅及深Handler消息机制 mp.weixin.qq.com/s/sJDzs4wnA…
消息队列:V8是怎么实现回调函数的? time.geekbang.org/column/arti…
秒懂消息队列 xie.infoq.cn/article/5e0…