我们通过以下这张图来加深对进程和线程的理解:概念二:堆、栈、队列如果你学过数据结构,就一定会遇到 "堆", "栈","队列",最关键的是即使你去面试,这些还都会问到,如果你不懂对你损失很大的。
- 进程好比图中的工厂,有单独的专属自己的工厂资源。当一个进程关闭之后,操作系统会回收进程所占用的内存。
- 线程好比图中的工人,多个工人在一个工厂中协作工作,工厂与工人是 1:n的关系。这意味着一个进程由一个或多个线程组成,进程中的任意一线程执行出错,都会导致整个进程的崩溃。
- 工厂的空间是工人们共享的,这意味着一个进程的内存空间是共享的,每个线程都可用这些共享内存。
- 多个工厂之间独立存在。这意味着进程之间的内容相互隔离。
1、堆是一种经过排序的树形数据结构,每个节点都有一个值,通常我们所说的堆的数据结构是指二叉树。
2、堆分为两种情况,有最大堆和最小堆。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
3、堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。
4、堆是应用程序在运行的时侯请求操作系统分配给自己内存,而不是在编译的时 ,一般是申请/给予的过程。
5、堆用来存储对象的值,并会用一个地址来记录存储值的位置,该地址存储在命名对象的变量中(即存储在栈内存中)。因此复制这个变量只是复制了地址,而不是复制了对象。
1、栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,把另一端称为栈底。不含任何数据元素的栈称为空栈。
2、栈是一种具有后进先出的数据结构,又称为后进先出的线性表,简称 LIFO(Last In First Out)结构。可以想象为一个桶,后放进去的东西会先拿出来,而且只能在桶口操作。
3、栈是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有FIFO的特性,在编译的时候可以指定需要的栈的大小。
4、栈定义了两个方法:PUSH操作在堆栈的顶部加入一个元素,POP操作相反,在堆栈顶部移去一个元素,并将堆栈的大小减一
1、队列是一种特殊的线性表,只允许在表的前端进行删除操作,表的后端进行插入操作,进行插入操作的端称为队尾,进行删除操作的端称为队头。
2、队列中没有元素时,称为空队列。
3、队列是一种先进先出的数据结构,又称为先进先出的线性表,简称 FIFO(First In First Out)结构。也就是说先放的先取,后放的后取,就如同行李过安检的时候,先放进去的行李在另一端总是先出来,后放入的行李会在最后面出来。
一个完整浏览器端的 Event Loop 过程,可以概括为以下阶段:JavaScript代码的具体流程
">">
主线程不断重复第三步,也就是 只要主线程空了,就会读取任务列表,该过程不断重复,这就是所谓的事件循环。
- 所有同步任务都在主线程上执行,形成一个执行栈 (Execution Context Stack)。我们可以把执行栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。
- 而异步任务会被放置到 Task Table,也就是上图中的异步处理模块,当异步任务有了运行结果,就将该函数移入任务队列。
- 一旦执行栈中的所有同步任务执行完毕,引擎就会读取任务队列,然后将任务队列中的第一个任务压入执行栈中运行。
总结:当某个宏任务执行完后,会查看是否有微任务队列。如果有,先执行微任务队列中的所有任务,如果没有,会读取宏任务队列中排在最前的任务,执行宏任务的过程中,遇到微任务,依次加入微任务队列。栈空后,再次读取微任务队列里的任务,依次类推。
timers 阶段:timers 阶段会执行 setTimeout 和 setInterval 回调,并且是由 poll 阶段控制的。 同样,在 Node 中定时器指定的时间也不是准确时间,只能是尽快执行。【4】宏队列、微队列
pending callbacks 阶段:这个阶段会执行一些和底层系统有关的操作,例如TCP连接返回的错误等。这些错误发生时,会被Node 推迟到下一个循环中执行。
poll 轮询阶段:poll 是一个至关重要的阶段,这一阶段中,系统会做两件事情:1、回到 timer 阶段执行回调 2、执行 I/O 回调。并且在进入该阶段时如果没有设定了 timer 的话,会发生以下两件事情:
当然设定了 timer 的话且 poll 队列为空,则会判断是否有 timer 超时,如果有的话会回到 timer 阶段执行回调。
- 如果 poll 队列不为空,会遍历回调队列并同步执行,直到队列为空或者达到系统限制
- 如果 poll 队列为空时,会有两件事发生
- 如果有 setImmediate 回调需要执行,poll 阶段会停止并且进入到 check 阶段执行回调
- 如果没有 setImmediate 回调需要执行,会等待回调被加入到队列中并立即执行回调,这里同样会有个超时时间设置防止一直等待下去
check 阶段:这个阶段会执行 setImmediate() 设置的任务。
close callbacks 阶段:如果一个 socket 或 handle(句柄) 突然被关闭了,例如通过 socket.destroy() 关闭了,close 事件将会在这个阶段发出。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |