-
Notifications
You must be signed in to change notification settings - Fork 1
Description
-
进程与线程
-
进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。将进程比喻为工厂的车间,它代表CPU所能处理的单个任务。
-
线程 是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元。把线程比喻一个车间的工人,即一个车间可以允许由多个工人协同完成一个任务。
-
进程与线程的关系: 1)进程是操作系统分配资源的最小单位,线程是程序执行的最小单位。 进程是cpu资源分配的最小单位; 2)一个进程由一个或多个线程组成;3)线程上下文切换比进程上下文切换要快得多;4)每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。但同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)
-
单线程与多线程,都是指在一个进程内的单和多。
-
-
多进程浏览器与单进程浏览器:
- 单进程浏览器(早期)带来的问题:
1.如果浏览器中的一个tab网页崩溃的话,将会导致其他被打开的网页应用;同理如果是单进程,插件崩溃了也会影响整个浏览器;
2.安全问题:
(对于单进程浏览器,线程之间有可能会恶意修改或者获取非授权数据等复杂的安全问题,进程之间是不共享资源和地址空间的,所以不会存在太多的安全问题)*
-
浏览器的进程:
- Browser进程浏览器界面显示(如前进,后退)、以及处理 web 浏览器不可见的特权部分,如网络请求与文件访问。
- 第三方插件进程每种类型的插件对应一个进程
- GPU进程最多一个,用于3D绘制等
- 浏览器渲染进程(渲染引擎、浏览器内核)默认每个Tab页面一个进程,互不影响。
对于普通的前端操作来说,最终要的是什么呢?答案是渲染进程。页面的渲染,JS的执行,事件的循环,都在这个进程内进行。浏览器的渲染进程是多线程的
-
关于渲染进程(每个tab页默认有一个渲染进程)
- GUI 渲染线程渲染界面(解析html、css,构建DOM树和渲染树,布局和绘制)、重绘或回流。当JS引擎线程执行时,这个线程就会被挂起,即“互斥”。
- JS引擎线程JavaScript引擎或者叫js内核用来处理js脚本,例如v8引擎。一个渲染进程中无论什么时候都只有一个JS线程在运行JS程序。(JS引擎是单线程的)
- 定时触发器线程
JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确,通过单独线程来控制。
- 事件触发线程用来控制事件循环。当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理
- 异步http请求线程在XMLHttpRequest在连接后是通过浏览器新开一个线程请求, 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件。
-
关于WebWorker
创建Worker时,JS引擎线程向浏览器申请开一个子线程(子线程是浏览器开的,完全受主线程控制,而且不能操作DOM);JS引擎线程与worker线程间通过特定的方式通信(postMessage API)。WebWorker只属于某个页面,不会和其他页面的Render进程(浏览器内核进程)共享。WebWorker只是属于render进程下的一个线程。
-
事件循环与渲染进程中的线程的关系:
- JS分为同步任务和异步任务。
- 同步任务都在主线程上执行,主线程运行时会产生执行栈。
- 主线程之外,栈中的代码调用某些api后,当满足触发条件后(如ajax请求完毕、定时器计时完成),事件触发线程就会在任务队列之中放置一个事件。事件触发线程管理任务队列(管理的是宏任务的事件队列)。
- 一旦执行栈中的所有同步任务执行完毕(此时JS引擎线程空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。
- 栈中的代码调用定时api后,定时器线程计时,计时完成,触发计时完成事件,事件触发线程将回调函数推入事件队列。
例如:
setTimeout(function(){
console.log('hello!');
}, 0);
console.log('begin');
这段代码的作用是当大于0ms(可能是4ms)计时完毕后(由定时器线程计时),将回调函数推入事件队列中(由事件触发线程完成),等待主线程执行(JS引擎线程执行)。HTML5规范规定最小延迟时间不能小于4ms,不过不同浏览器最小时间设定可能不同
执行一个宏任务 -》 执行过程中如果遇到微任务,就将它添加到微任务的任务队列(Job Queues)中 -》 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行) -》 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染 -》 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件触发线程管理的事件队列中获取)
以下为补充:
-
Browser进程
上图仅列出了Browser进程里的2个线程:UI线程和IPC线程。
- UI线程是主线程,主要负责整个UI的渲染和消息的响应,包括自身的消息和从Render 进程发过来的消息。
- IPC线程(IO线程) 负责Browser进程与Render进程之间的通信和网络资源消息的过滤。
- RenderProcessHost在主线程上初始化时会同时创建了一个新的Renderer进程和一个ChannelProxy IPC对象实例,这个IPC::ChannelProxy会建立一个命名管道连接到Renderer进程。
- 一个RenderProcessHost负责跟一个Renderer进程通信 (一对一)
-
关于浏览器进程与进程间通信
在Chrome中,用到的就是有名的管道(Named Pipe),只不过,它用一个IPC::Channel类,封装了具体的实现细节。在每一个进程中,只能有一个线程来负责操作Channel,这个线程叫做IO线程。
-
关于Bitmap
屏幕上看到的图像都是由一个一个的像素组成的,这些像素就是存放在Bitmap中。可以认为Bitmap就是用来直接展示在窗口上的一个显示对象。
-
关于共享内存
共享内存是进程间通信中最简单的方式之一,也是进程间共享数据的一种最快的方法。共享内存允许两个或更多进程访问同一块内存。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。
-
Browser和Renderer通信过程(**为修改补充的)
- Browser进程收到用户请求,首先UI线程处理,转交给IO线程(IPC线程),随后通过RenderProcessHost接口转交给Renderer进程。
- Renderer进程的Renderer接口收到消息,IO线程简单处理后,交给渲染线程。
- GUI 渲染线程(解析html、构建DOM树、解析css、构建CSS树) =》 JS引擎线程(JS执行)=》 GUI 渲染线程(RenderObject树构建、布局和绘制)生成用户可见区域(ViewPort)的Bitmap。这里是将内容绘制到一个使用共享内存存储的bitmap。**最后Render进程将结果由IO线程传递给Browser进程**
- **Browser进程将Renderer进程得到的内存中的Bitmap,绘制到用户界面上。**
- 个人理解:将网页内容理解成一张图片,Renderer进程在共享内存中绘制了这张图片(即Bitmap),Browser进程在共享内存中拿到这种图片并展示。