浏览器进程线程1

27次阅读

共计 3329 个字符,预计需要花费 9 分钟才能阅读完成。

本篇文章参考自撒网要见鱼大佬的 仅供自己学习提升。
https://segmentfault.com/a/11…
区分线程和进程
**- 什么是进程 **

狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。

广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

**- 什么是线程 **

线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

在当代面向线程设计的计算机结构中,进程是线程的容器。
先看个形象的比喻:
– 进程是一个工厂,工厂有它的独立资源

– 工厂之间相互独立

– 线程是工厂中的工人,多个工人协作完成任务

– 工厂内有一个或多个工人

– 工人之间共享空间

再完善完善概念:
– 工厂的资源 -> 系统分配的内存(独立的一块内存)

– 工厂之间的相互独立 -> 进程之间相互独立

– 多个工人协作完成任务 -> 多个线程在进程中协作完成任务

– 工厂内有一个或多个工人 -> 一个进程由一个或多个线程组成

– 工人之间共享空间 -> 同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)

然后再巩固下:
可以打开任务管理器,可以看到有一个后台进程列表。这里就是查看进程的地方,而且可以看到每个进程的内存资源信息以及 cpu 占有率。

浏览器是多线程的
理解了进程与线程了区别后,接下来对浏览器进行一定程度上的认识:(先看下简化理解)

浏览器是多进程的
浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存)
简单点理解,每打开一个 Tab 页,就相当于创建了一个独立的浏览器进程。

图中打开了 Chrome 浏览器的多个标签页,然后可以在 Chrome 的任务管理器中看到有多个进程(分别是每一个 Tab 页面有一个独立的进程,以及一个主进程)。
注意:在这里浏览器应该也有自己的优化机制,有时候打开多个 tab 页后,可以在 Chrome 任务管理器中看到,有些进程被合并了
浏览器都包含哪些进程?
主要包含哪些进程:(为了简化理解,仅列举主要进程)

Browser 进程:浏览器的主进程(负责协调、主控),只有一个。作用有

负责浏览器界面显示,与用户交互。如前进,后退等
负责各个页面的管理,创建和销毁其他进程
将 Renderer 进程得到的内存中的 Bitmap,绘制到用户界面上
网络资源的管理,下载等

第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
GPU 进程:最多一个,用于 3D 绘制等

浏览器渲染进程(浏览器内核)(Renderer 进程,内部是多线程的):默认每个 Tab 页面一个进程,互不影响。主要作用为
页面渲染,脚本执行,事件处理等

强化记忆:在浏览器中打开一个网页相当于新起了一个进程(进程内有自己的多线程)
浏览器多进程的优势
相比于单进程浏览器,多进程有如下优点:

避免单个 page crash 影响整个浏览器
避免第三方插件 crash 影响整个浏览器
多进程充分利用多核优势
方便使用沙盒模型隔离插件等进程,提高浏览器稳定性简单点理解:如果浏览器是单进程,那么某个 Tab 页崩溃了,就影响了整个浏览器,体验有多差;同理如果是单进程,插件崩溃了也会影响整个浏览器;

重点是浏览器内核(渲染进程)
对于普通的前端操作来说,页面的渲染,JS 的执行,事件的循环,都在这个进程内进行。浏览器的渲染进程是多线程的。
渲染进程包含哪些主要的线程?
1.GUI 渲染线程【图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)】

负责渲染浏览器界面,解析 HTML,CSS,构建 DOM 树和 RenderObject 树,布局和绘制等。
当界面需要重绘(Repaint)或由于某种操作引发回流 (reflow) 时,该线程就会执行
注意,GUI 渲染线程与 JS 引擎线程是互斥的,当 JS 引擎执行时 GUI 线程会被挂起(相当于被冻结了),GUI 更新会被保存在一个队列中等到 JS 引擎空闲时立即被执行。

2.JS 引擎线程

也称为 JS 内核,负责处理 Javascript 脚本程序。(例如 V8 引擎)
JS 引擎线程负责解析 Javascript 脚本,运行代码。
JS 引擎一直等待着任务队列中任务的到来,然后加以处理,一个 Tab 页(renderer 进程)中无论什么时候都只有一个 JS 线程在运行 JS 程序
同样注意,GUI 渲染线程与 JS 引擎线程是互斥的,所以如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。

3. 事件触发线程

归属于浏览器而不是 JS 引擎,用来控制事件循环(可以理解,JS 引擎自己都忙不过来,需要浏览器另开线程协助)
当 JS 引擎执行代码块如 setTimeOut 时(也可来自浏览器内核的其他线程, 如鼠标点击、AJAX 异步请求等),会将对应任务添加到事件线程中
当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待 JS 引擎的处理(事件循环 Event Loop)
注意,由于 JS 的单线程关系,所以这些待处理队列中的事件都得排队等待 JS 引擎处理(当 JS 引擎空闲时才会去执行)

4. 定时触发器线程

传说中的 setInterval 与 setTimeout 所在线程
浏览器定时计数器并不是由 JavaScript 引擎计数的,(因为 JavaScript 引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)
因此通过单独线程来计时并触发定时【计时完毕后,添加到事件队列中,等待 JS 引擎空闲后执行,这也是“JavaScript 定时器不准确”的原因(可用 requestAnimationFrame)】
注意,W3C 在 HTML 标准中规定,规定要求 setTimeout 中低于 4ms 的时间间隔算为 4ms。

5. 异步 http 请求线程

在 XMLHttpRequest 在连接后是通过浏览器新开一个线程请求
将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由 JavaScript 引擎执行。

为什么 JS 引擎是单线程的?为什么需要异步? 单线程又是如何实现异步的呢? 查看【链接描述】
Browser 进程和浏览器内核(Renderer 进程)的通信过程
如果自己打开任务管理器,然后打开一个浏览器,就可以看到:任务管理器中出现了两个进程(一个是主控进程,一个则是打开 Tab 页的渲染进程),然后在这前提下,看下整个的过程:(简化了很多)

Browser 进程收到用户请求,首先需要获取页面内容(譬如通过网络下载资源),随后将该任务通过 RendererHost 接口传递给 Render 进程

Renderer 进程的 Renderer 接口收到消息,简单解释后,交给渲染线程,然后开始渲染

渲染线程接收请求,加载网页并渲染网页,这其中可能需要 Browser 进程获取资源和需要 GPU 进程来帮助渲染
当然可能会有 JS 线程操作 DOM(这样可能会造成回流并重绘)
最后 Render 进程将结果传递给 Browser 进程

Browser 进程接收到结果并将结果绘制出来

这里绘一张简单的图:(很简化)

梳理浏览器内核中线程之间的关系
GUI 渲染线程与 JS 引擎线程互斥
由于 JavaScript 是可操纵 DOM 的,如果在修改这些元素属性同时渲染界面(即 JS 线程和 UI 线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。
因此为了防止渲染出现不可预期的结果,浏览器设置 GUI 渲染线程与 JS 引擎为互斥的关系,当 JS 引擎执行时 GUI 线程会被挂起,GUI 更新则会被保存在一个队列中等到 JS 引擎线程空闲时立即被执行。
从上述的互斥关系,可以推导出,JS 如果执行时间过长就会阻塞页面。
譬如,假设 JS 引擎正在进行巨量的计算,此时就算 GUI 有更新,也会被保存到队列中,等待 JS 引擎空闲后执行。然后,由于巨量计算,所以 JS 引擎很可能很久很久后才能空闲,自然会感觉到巨卡无比。
所以,要尽量避免 JS 执行时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

正文完
 0