前言
转载文章链接:https://segmentfault.com/a/1190000020077274
下方内容是对其中我需要的基础知识和之前存在有困惑的地方进行的提取,方便想了解基础的人看。但是想要深入了解Node,推荐看上述链接的原文章。
另外我也是刚刚学习Node,如果文章中有存在理解错误,麻烦帮提出来,我进行修改,十分感谢!
进程定义
进程Process是系统进行资源分配和调度的基本单位,是操作系统结构的基础,进程是线程的容器。
直接理解,进程是资源分配的最小单位。我们启动一个服务、运行一个实例,就是开一个服务进程,例如:Node.js 里通过 node app.js 开启一个服务进程
多进程就是进程的复制(fork),fork 出来的每个进程都拥有自己的独立空间地址、数据栈,一个进程无法访问另外一个进程里定义的变量、数据结构,只有建立了 IPC 通信,进程之间才可数据共享。
线程定义
线程是操作系统能够进行运算调度的最小单位,注意:线程是隶属于进程的,被包含于进程之中。一个线程只能隶属于一个进程,但是一个进程是可以拥有多个线程的。
单线程
单线程就是一个进程只开一个线程。其中JS就是单线程,程序顺序执行(异步先不考虑)。
单线程说明:
1.Node.js是单线程模式,但是其基于事件驱动、异步非阻塞模式,可以应用于高并发场景
2.单线程无法利用多核CPU
Node.js
Node.js 是 JS 在服务端的运行环境,构建在 chrome 的 V8 引擎之上,基于事件驱动、非阻塞I/O模型,充分利用操作系统提供的异步 I/O 进行多任务的执行,适合于 I/O 密集型的应用场景。因为异步,程序无需阻塞等待结果返回,而是基于回调通知的机制,原本同步模式等待的时间,则可以用来处理其它任务。
开发模式:
在单核 CPU 系统之上,采用 单进程 + 单线程 模式。
在多核 CPU 系统之上,采用 多进程 + 单线程 模式。(可采用 Cluster 等方法来实现多进程架构 )。注意:开启多进程不是为了解决高并发,主要是解决了单进程模式下 Node.js CPU 利用率不足的情况,充分利用多核 CPU 的性能。
多进程说明:
虽然fork 确实可以开启多个进程,但是并不建议衍生出来太多的进程,通长根据系统 CPU 核心数设置。
cpu核心数的获取方式const cpus = require(‘os’).cpus().length,这里 cpus 返回一个对象数组,包含所安装的每个 CPU/内核的信息。假设主机装有两个cpu,每个cpu有4个核,那么总核数就是8。
Node.js 进程间通信
IPC这个词只要提到进程通信,都会提到它。IPC的全称是Inter-Process Communication,即进程间通信。它的目的是为了让不同的进程能够互相访问资源并进行协调工作。
实现进程间通信的技术有很多,如命名管道,匿名管道,socket,信号量,共享内存,消息队列等。Node中实现IPC通道是依赖于libuv。windows下由命名管道(name pipe)实现,*nix系统则采用Unix Domain Socket实现。表现在应用层上的进程间通信只有简单的message事件和send()方法,接口十分简洁和消息化。
IPC创建和实现示意图:
父进程在实际创建子进程之前,会创建IPC通道并监听它,然后才真正的创建出子进程,这个过程中也会通过环境变量(NODE_CHANNEL_FD)告诉子进程这个IPC通道的文件描述符。子进程在启动的过程中,根据文件描述符去连接这个已存在的IPC通道,从而完成父子进程之间的连接。
IPC通信管道创建示意图:
解疑
1.Node.js关于单线程的误区
const http = require('http');
const server = http.createServer();
server.listen(3000,()=>{
process.title='程序员成长指北测试进程';
console.log('进程id',process.pid)
})
仍然看本文第一段代码,创建了http服务,开启了一个进程,都说了Node.js是单线程,所以 Node 启动后线程数应该为 1,但实际是7个
解释一下这个原因:
Node 中最核心的是 v8 引擎,在 Node 启动后,会创建 v8 的实例,这个实例是多线程的。
- 主线程:编译、执行代码。
- 编译/优化线程:在主线程执行的时候,可以优化代码。
- 分析器线程:记录分析代码运行时间,为 Crankshaft优化代码执行提供依据。
- 垃圾回收的几个线程。
所以大家常说的 Node 是单线程的指的是 JavaScript 的执行是单线程的(开发者编写的代码运行在单线程环境中),但 Javascript 的宿主环境,无论是 Node 还是浏览器都是多线程的。因为libuv中有线程池的概念存在的,libuv会通过类似线程池的实现来模拟不同操作系统的异步调用,这对开发者来说是不可见的。
2. Libuv
Libuv 是一个跨平台的异步IO库,它结合了UNIX下的libev和Windows下的IOCP的特性,最早由Node的作者开发,专门为Node提供多平台下的异步IO支持。Libuv本身是由C++语言实现的,Node中的非苏塞IO以及事件循环的底层机制都是由libuv实现的。
注意:
Node的异步调用是由libuv来支持的,以读取文件为例子,读文件实质的系统调用是由libuv来完成的,Node只是负责调用libuv的接口,等数据返回后再执行对应的回调方法。