Chromium 是如何解决队头阻塞问题的

简介: 【1月更文挑战第4天】

为了解决由于单消息队列而造成的队头阻塞问题,Chromium 团队从 2013 年到现在,花了大量的精力在持续重构底层消息机制。


1、第一次迭代:引入一个高优先级队列


首先在最理想的情况下,我们希望能够快速跟踪高优先级任务,比如在交互阶段,下面几种任务都应该视为高优先级的任务:

  • 通过鼠标触发的点击任务、滚动页面任务;
  • 通过手势触发的页面缩放任务;
  • 通过 CSS、JavaScript 等操作触发的动画特效等任务。


这些任务被触发后,用户想立即得到页面的反馈,所以我们需要让这些任务能够优先与其他的任务执行。要实现这种效果,我们可以增加一个高优级的消息队列,将高优先级的任务都添加到这个队列里面,然后优先执行该消息队列中的任务。最终效果如下图所示:

我们使用了一个优先级高的消息队列和一个优先级低消息队列,渲染进程会将它认为是紧急的任务添加到高优先级队列中,不紧急的任务就添加到低优先级的队列中。然后我们再在渲染进程中引入一个任务调度器,负责从多个消息队列中选出合适的任务,通常实现的逻辑,先按照顺序从高优先级队列中取出任务,如果高优先级的队列为空,那么再按照顺序从低优级队列中取出任务。


将任务划分为多个不同的优先级,来实现更加细粒度的任务调度,比如可以划分为高优先级,普通优先级和低优先级,最终效果如下图所示:

我们实现了三个不同优先级的消息队列,然后可以使用任务调度器来统一调度这三个不同消息队列中的任务。


现在我们引入了多个消息队列,结合任务调度器我们就可以灵活地调度任务了,这样我们就可以让高优先级的任务提前执行,采用这种方式似乎解决了消息队列的队头阻塞问题。


2、 第二次迭代:根据消息类型来实现消息队列


要解决上述问题,我们可以为不同类型的任务创建不同优先级的消息队列,比如:

  • 可以创建输入事件的消息队列,用来存放输入事件。
  • 可以创建合成任务的消息队列,用来存放合成事件。
  • 可以创建默认消息队列,用来保存如资源加载的事件和定时器回调等事件。
  • 还可以创建一个空闲消息队列,用来存放 V8 的垃圾自动垃圾回收这一类实时性不高的事件。


通过迭代,这种策略已经相当实用了,但是它依然存在着问题,那就是这几种消息队列的优先级都是固定的,任务调度器会按照这种固定好的静态的优先级来分别调度任务。


3、第三次迭代:动态调度策略


根据实际场景来继续平衡这个跷跷板,也就是说在不同的场景下,根据实际情况,动态调整消息队列的优先级。一图胜过千言,我们先看下图:


这张图展示了 Chromium 在不同的场景下,是如何调整消息队列优先级的。通过这种动态调度策略,就可以满足不同场景的核心诉求了,同时这也是 Chromium 当前所采用的任务调度策略。


上图列出了三个不同的场景,分别是加载过程,合成过程以及正常状态。当渲染进程接收到用户交互的任务后,接下来大概率是要进行绘制合成操作,因此我们可以设置,当在执行用户交互的任务时,将合成任务的优先级调整到最高。


接下来,处理完成 DOM,计算好布局和绘制,就需要将信息提交给合成线程来合成最终图片了,然后合成线程进入工作状态。现在的场景是合成线程在工作了,那么我们就可以把下个合成任务的优先级调整为最低,并将页面解析、定时器等任务优先级提升。


4、第四次迭代:任务饿死


不过依然存在一个问题,那就是在某个状态下,一直有新的高优先级的任务加入到队列中,这样就会导致其他低优先级的任务得不到执行,这称为任务饿死。Chromium 为了解决任务饿死的问题,给每个队列设置了执行权重,也就是如果连续执行了一定个数的高优先级的任务,那么中间会执行一次低优先级的任务,这样就缓解了任务饿死的情况。

相关文章
|
2月前
|
算法 Java 数据库
Android 应用的主线程在什么情况下会被阻塞?
【10月更文挑战第20天】为了避免主线程阻塞,我们需要合理地设计和优化应用的代码。将耗时操作移到后台线程执行,使用异步任务、线程池等技术来提高应用的并发处理能力。同时,要注意避免出现死循环、不合理的锁使用等问题。通过这些措施,可以确保主线程能够高效地运行,提供流畅的用户体验。
78 2
|
5月前
|
编译器 C语言 iOS开发
iOS 16 系统键盘修复问题之确定_lock是否用于保护对_deferredTasks的多线程读写如何解决
iOS 16 系统键盘修复问题之确定_lock是否用于保护对_deferredTasks的多线程读写如何解决
|
6月前
|
存储 JavaScript 前端开发
在?聊聊浏览器事件循环机制
在?聊聊浏览器事件循环机制
55 0
|
8月前
|
消息中间件 缓存 JavaScript
“别让你的代码卡住了”——事件循环机制大揭秘
“别让你的代码卡住了”——事件循环机制大揭秘
|
8月前
|
缓存 小程序 前端开发
如何解决小程序异步请求问题
如何解决小程序异步请求问题
206 0
|
安全 调度 开发者
并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3
协程与线程向来焦孟不离,但事实上是,线程更被我们所熟知,在Python编程领域,单核同时间内只能有一个线程运行,这并不是什么缺陷,这实际上是符合客观逻辑的,单核处理器本来就没法同时处理两件事情,要同时进行多件事情本来就需要正在运行的让出处理器,然后才能去处理另一件事情,左手画方右手画圆在现实中本来就不成立,只不过这个让出的过程是线程调度器主动抢占的。
并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3
|
移动开发 JavaScript 前端开发
前端开发面试题—JavaScript执行机制(同步与异步,补充:线程与进程)
今天分享一下我遇到的一个面试题,是关于JavaScript执行机制——同步与异步的问题,解释一下什么是同步和异步呢?
265 0
前端开发面试题—JavaScript执行机制(同步与异步,补充:线程与进程)
|
存储 Web App开发 缓存
浏览器专题系列 - 事件循环机制
浏览器专题系列 - 事件循环机制
|
调度 Android开发 Java
详解 RxJava2 的线程切换原理
转载请标明地址 QuincySx:[https://www.jianshu.com/p/a9ebf730cd08 ] 读了这篇文章你将会收获什么 RxJava2 基本的运行流程(并不会详述) RxJava2 线程切换原理 为什么 subscri...
2228 0

热门文章

最新文章