2

进程 和 线程

进程

进程:是操作系统对一个正在运行的程序的一种抽象,在一个系统上可以同时运行务个

进程,而每个进程都好像在独占地使用硬件。

打开多个程序,是一个进程的指令和另一个进程的指令是交错执行的。在大多数系统中,需要运行的进程数是多于可以运行它们的CPU个数的。传统系统在一个时刻只能执行一个程序,而先进的多核处理器同时能够执行多个程序。无论是在单核还是多核系统中,一个CPU看上去都像是在并发地执行多个进程(CPU太太太快了,那当多个任务要执行的时候怎么办呢?轮流着来?或者谁优先级高谁来?不管怎么样的策略,一句话就是在CPU看来就是轮流着来),这是通过处理器在进程间切换来实现的.操作系统实现这种交错执行的机制称为上下文切换

上下文切换:操作系统保持跟踪进程运行所需的所有状态信息。这种状态也就是上下文,包括许多信息,比如 PC 和寄存器文件的当前值,以及主存的内容(进程是cpu资源分配的最小单位)。在任何一个时刻,单处理希系统都只能执行一个进程的代码.当操作系统决定要把控制权从当前进程转移到某个新进程时,就会进行上下丈切挽,即保存当前进程的上下文(等着下一次 CPU 临幸)、恢复新进程的上下文,然后将控制权传递到新进程。新进程就会从它上次停止的地方开始。

线程

一个进程实际上可以由多个称为线程的 执行単元 组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。

比喻:

进程的颗粒度太大,每次都要有上下的调入,保存,调出。一个运行在电脑上的软件,那么一个软件的执行不可能是一条逻辑就能执行完的,必定有多个分支和多个程序段,就好比要实现程序A,实际分成 a,b,c等多个块组合而成。那么这里具体的执行就可能变成:

程序A得到CPU临幸:CPU加载上下文,开始执行程序 A 的 a 小段,然后执行A的 b 小段,然后再执行A的 c 小段,最后CPU保存A的上下文。

这里a,b,c的执行是共享了A的上下文,CPU在执行的时候没有进行上下文切换的。这里的a,b,c就是线程,也就是说线程是共享了进程的上下文环境,的更为细小的CPU时间段。

Node

线程是cpu调度的一个基本单位,一个cpu同时只能执行一个线程的任务,同样一个线程任务也只能在一个cpu上执行

  • 这个线程挂掉后整个程序就会挂掉;
  • 所以如果你运行Node.js的机器是像i5,i7这样多核cpu无法充分利用多核资源

Event loop

事件循环是 node 处理非阻塞 I/O 操作的机制。

macro-task 大概包括:

  • setTimeout
  • setInterval
  • setImmediate
  • script(整体代码)
  • I/O 操作等。

micro-task 大概包括:

  • process.nextTick(与普通微任务有区别,在微任务队列执行之前执行)
  • new Promise().then() 回调等。

下面的图表展示了事件循环操作顺序的简化概览:

每个框被称为事件循环机制的一个阶段

每个阶段都有一个 FIFO 队列来执行回调。虽然每个阶段都是特殊的,但通常情况下,当事件循环进入给定的阶段时,它将执行特定于该阶段的任何操作,然后执行该阶段队列中的回调,直到队列用尽或最大回调数已执行。当该队列已用尽或达到回调限制,事件循环将移动到下一阶段.

各个 Node 版本有差异,以 Node 11 往后的版本讨论,它比较趋于和浏览器行为一致:一旦执行一个阶段里的一个宏任务(setTimeout, setInterval和 setImmediate),就立刻执行对应的微任务队列

阶段概述

  • 定时器:本阶段执行已经被 ​setTimeout()​ 和 ​setInterval()​ 的调度回调函数。
  • 待定回调:执行延迟到下一个循环迭代的 I/O 回调。
  • idle, prepare:仅系统内部使用。
  • 轮询:检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 ​setImmediate()​ 调度的之外),其余情况 node 将在适当的时候在此阻塞。
  • 检测:​setImmediate()​ 回调函数在这里执行。
  • 关闭的回调函数:一些关闭的回调函数,如:​socket.on('close', ...)​。

child_process

使用方法 :    

  • spawn spawn('node', ['worker.js']) 启动一个字进程来执行命令   
  • exec exec('node worker.js', (err, stdout, stderr) => {}) 启动一个子进程来执行命令,有回调
  • execFile('worker.js') 启动一个子进程来执行可执行的文件

(头部要添加#!/usr/bin/env node)   

  • fork('worker.js') ,不过这里只需要自定js文件模块即可

子进程创建服务的时候,多个进程监听一个端口:

  • 最简单的就是每个子进程都使用不同的端口
  • 第二种方案是,在主进程进行端口的监听,然后将监听的套接字传给子进程。

cluster

它可以通过一个父进程管理一堆子进程的方式来实现集群的功能。

cluster 底层就是 child_process。

进程守护

  • 普通的逻辑错误:监听 uncaughtException
  • 僵尸进程(进程存在,但是啥活都干不了):心跳检测(每个 1min 我给你发一条消息,如果超过3次你没有回复我,认为你心跳停止)
  • 内存监控

酷吧你我他
59 声望12 粉丝

小白一枚,专写bug


« 上一篇
https