进程和线程,同步和异步
进程与线程
一个程序中至少有一个进程,而一个进程中至少有一个线程
- 进程是运行中的程序,线程是进程内部的一个执行序列
- 进程是资源分配的单元,线程是执行单元
- 进程间切换代价大,线程间切换代价小
- 进程拥有的资源多,线程拥有的资源少
- 多个线程共享进程的资源
如:
工厂的资源 -> 系统分配的内存(独立的一块内存)
工厂之间的相互独立 -> 进程之间相互独立
多个工人协作完成任务 -> 多个线程在进程中协作完成任务
工厂内有一个或多个工人 -> 一个进程由一个或多个线程组成
工人之间共享空间 -> 同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)
浏览器是多进程的!!!
浏览器的进程:
- Browser进程:浏览器的主进程(负责协调、主控),只有一个 负责浏览器界面显示,与用户交互。如前进后退
- 负责各个页面的管理,创建和销毁其他进程
- 将Renderer进程得到的内存中的Bitmap,会知道用户界面上
- 网络资源的管理,下载等
-
页面渲染、脚本执行、事件处理
重点:浏览器内核(渲染进程)
渲染进程是多线程的
包含:
- GUI渲染线程 负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
- 当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行
- 注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行
-
也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)
-
归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)
-
传说中的setInterval与setTimeout所在线程
-
在XMLHttpRequest在连接后是通过浏览器新开一个线程请求
单线程与多线程
单线程
所谓单线程(主线程),指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。
多线程
如浏览器的渲染进程:
- GUI渲染线程
- JS引擎线程
- 事件触发线程
- 定时器触发线程
- 异步http请求线程
同步和异步
同步:如果在函数返回的时候,调用者就能够得到预期结果(即拿到了预期的返回值或者看到了预期的效果),那么这个函数就是同步的
例如:
console.log('我是第一件事'); console.log('我是第二件事');
1.这两个函数都是同步的
2.这段代码是同步的
3.若有一个函数执行时间很长,后面的函数只能等待这个函数执行完才能执行(同步是阻塞的)
异步
先来看段代码:
console.log('我是第一件事'); setTimeout(function () { console.log('我突然有事,晚点再做第二件事'); },1000) console.log('我是第三件事'); //我是第一件事 //我是第三件事 //我突然有事,晚点再做第二件事
这段代码实现的就是异步
1.执行console.log('我是第一件事')
2.setTimeout异步函数跳过
3.执行console.log('我是第三件事')
4.js引擎空闲1秒后将异步函数推入事件队列-->执行console.log('我突然有事,晚点再做第二件事')
补充:setTimeout和setInterval接受两个参数,第一个参数为函数。第二个为时间(毫秒),及js引擎空闲几秒后将其推入事件队列。
再来一个:
console.log(0,'第一'); for (let i = 0;i<3;i++){ setTimeout(function(){ console.log(i,'第三'); },2000) console.log(i,'第二'); }; //0 "第一" //0 "第二" //1 "第二" //2 "第二" //两秒之后 //0 "第三" //1 "第三" //2 "第三"
补充:
- 异步机制是浏览器的两个或两个以上的常驻线程共同完成的
- 如:异步请求是由两个常驻线程:JS执行线程和事件触发线程共同完成的,JS的执行线程发起异步请求(这时浏览器会开一条新的HTTP请求线程来执行请求,这时JS的任务已完成,继续执行线程队列中剩下的其他任务),然后在未来的某一时刻事件触发线程监视到之前的发起的HTTP请求已完成,它就会把完成事件插入到JS执行队列的尾部等待JS处理。
- 如:定时触发(settimeout和setinterval)是由浏览器的定时器线程执行的定时计数,然后在定时时间把定时处理函数的执行请求插入到JS执行队列的尾端
消息队列与事件循环
如上图所示:
- 左边的栈存储的是同步任务,就是那些能立即执行、不耗时的任务,如变量和函数的初始化、事件的绑定等等那些不需要回调函数的操作都可归为这一类。
- 右边的堆用来存储声明的变量、对象。
- 下面的队列就是消息队列,一旦某个异步任务有了响应就会被推入队列中。如用户的点击事件、浏览器收到服务的响应和setTimeout中待执行的事件,每个异步任务都和回调函数相关联。
JS引擎线程用来执行栈中的同步任务,当所有同步任务执行完毕后,栈被清空,然后读取消息队列中的一个待处理任务,并把相关回调函数压入栈中,单线程开始执行新的同步任务。
JS引擎线程从消息队列中读取任务是不断循环的,每次栈被清空后,都会在消息队列中读取新的任务,如果没有新的任务,就会等待,直到有新的任务,这就叫事件循环。
以Ajax异步请求为例:
实例
最后来个大的:
setTimeout(function(){ for(var i = 0; i < 100000000; i++){} console.log('timer a'); }, 0) for(var j = 0; j < 5; j++){ console.log(j); } setTimeout(function(){ console.log('timer b'); }, 0) function waitFiveSeconds(){ var now = (new Date()).getTime(); while(((new Date()).getTime() - now) < 5000){} console.log('finished waiting'); } document.addEventListener('click', function(){ console.log('click'); }) console.log('click begin'); waitFiveSeconds(); //0 //1 //2 //3 //4 //click begin //finished waiting //timer a //timer b //click
再说一下:setTimeout(fn,0);是js引擎空闲后立即插入队列,并不是立即执行
1.第一个setTimeout异步函数跳过
2.执行for循环输出0,1,2,3,4
3.第二个setTimeout异步函数跳过
4.执行console.log('click begin')输出 click begin
5.调用waitFiveSeconds()函数输出finished waiting
6.waitFiveSeconds()执行完后同步任务结束,js引擎空闲会一次将异步函数插入队列
7.输出timer a;timer b;click
- Python 中的进程、线程、协程、同步、异步、回调
- Python 中的进程、线程、协程、同步、异步、回调
- iOS中多线程知识总结:进程、线程、GCD、串行队列、并行队列、全局队列、主线程队列、同步任务、异步任务等
- iOS 多线程 进程、线程、并发、串行、同步、异步—— iOS 编码复习(四)(多线程2)
- 并发,并行,进程,线程,同步,异步
- 线程进程/同步异步
- 进程,线程,同步,异步,内存管理小结
- Python 中的进程、线程、协程、同步、异步、回调
- 阻塞 非阻塞 同步 异步 线程 进程 任务
- 【pthread系列-1】同步异步线程进程的一些思考
- Python 中的进程、线程、协程、同步、异步、回调
- 浅析 线程 进程 阻塞 非阻塞 同步 异步整理
- Python 中的进程、线程、协程、同步、异步、回调
- Python 中的进程、线程、协程、同步、异步、回调(一)
- 11.python并发入门(part1 初识进程与线程,并发,并行,同步,异步)
- 深入浅出:进程、线程、协程、同步、异步、回调(转载)
- 进程 线程 多线程 并发 同步异步
- 让那些做面试官的屌丝lead不再抖脚系列(一)---同步异步探讨->进程和线程
- Python 中的进程、线程、协程、同步、异步、回调
- Python 中的进程、线程、协程、同步、异步、回调