前后端都用的编程模型--消息队列

81 阅读4分钟

前言

某个不眠之夜,你的安卓手机响了。

拿起手机一看,原来是家人/朋友/老板等给你一条微信。

你想了一会,决定查看这条信息。

你解锁了手机,点开消息通知,看到显示的文字后,你沉思了几秒钟/分钟。

过了一会,你想好了要回复的文字。

你点击文本输入框,在弹出的输入法键盘敲打,形成了要发送的文字片段,然后点击“发送”按钮。

过一会,你的联系人会收到你发的文字。

这一切的背后,究竟有什么黑科技?让我们来走进科学(大误)

简要介绍

现代计算机(包括日常用的智能手机),每个应用至少占用一个进程(有些大型应用,如微信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…

更多文章和有用工具看这里