人所缺乏的不是才干而是志向,不是成功的能力而是勤劳的意志。 —— 部尔卫
前言
一提到 Node.js ,我想大家都会想到它的一个特点,单线程。但是 Node.js 在运行的时候依赖 V8 这个宿主环境,难道在宿主环境中也是单线程吗?请看正文解释你这个疑惑。
作者简介:koala,专注完整的 Node.js 技术栈分享,从 JavaScript 到 Node.js,再到后端数据库,祝您成为优秀的高级 Node.js 工程师。公众号【程序员成长指北】作者,Github 博客开源项目 https://github.com/koala-coding/goodBlog
Node.js 单线程误区
开启 Node.js 服务 Demo
const http = require('http');
const server = http.createServer();
server.listen(3000,()=>{
process.title='程序员成长指北测试进程';
console.log('进程id',process.pid)
})
看这段代码,创建了http服务,开启了一个进程,都说了Node.js是单线程,所以 Node 启动后线程数应该为 1,但是事实并非如此,呜呜呜。
看活动监视器怎么开启7个线程呢?难道Javascript不是单线程不知道小伙伴们有没有这个疑问?
解释一下这个原因:
Node 中最核心的是 v8 引擎,在 Node 启动后,会创建 v8 的实例,这个实例是多线程的。
- 主线程:编译、执行代码。
- 编译/优化线程:在主线程执行的时候,可以优化代码。
- 分析器线程:记录分析代码运行时间,为 Crankshaft 优化代码执行提供依据。
- 垃圾回收的几个线程。
所以大家常说的 Node 是单线程的指的是 JavaScript 的执行是单线程的(开发者编写的代码运行在单线程环境中),但 Javascript 的宿主环境,无论是 Node 还是浏览器都是多线程的因为 libuv 中有线程池的概念存在的,libuv 会通过类似线程池的实现来模拟不同操作系统的异步调用,这对开发者来说是不可见的。
V8中什么时候会创建额外进程
某些异步 IO 会占用额外的线程
还是上面那个例子,我们在定时器执行的同时,去读一个文件:
const fs = require('fs')
setInterval(() => {
console.log(new Date().getTime())
}, 3000)
fs.readFile('./kaola.html', () => {})
线程数量变成了 11 个,这是因为在 Node 中有一些 IO 操作(DNS,FS)和一些 CPU 密集计算(Zlib,Crypto)会启用 Node 的线程池,而线程池默认大小为 4,因为线程数变成了 11。
手动更改线程池默认大小:
process.env.UV_THREADPOOL_SIZE = 64
修改线程池默认大小后,线程的数量变成 71。
Libuv
Libuv 是一个跨平台的异步 IO 库,它结合了 UNIX 下的 libev 和 Windows 下的 IOCP 的特性,最早由 Node.js 的作者开发,专门为 Node.js 提供多平台下的异步IO支持。Libuv 本身是由 C++ 语言实现的,Node.js 中的非阻塞 IO 以及事件循环的底层机制都是由 libuv 实现的。
libuv架构图
在 Windows 环境下,libuv 直接使用Windows的 IOCP 来实现异步IO。在 非Windows 环境下,libuv使用多线程(线程池Thread Pool)来模拟异步IO,这里仅简要提一下 libuv 中有线程池的概念,之后的文章会介绍 libuv 如何实现进程间通信。
注意下面我要说的话:
Node的异步调用是由 libuv 来支持的,以上面的读取文件的例子,读文件实质的系统调用是由 libuv 来完成的,Node只是负责调用 libuv 的接口,等数据返回后再执行对应的回调方法。
总结
本篇文章对 Node.js 的单线程误区做了讲解,不过本篇文章只是 Node.js 高级进阶之进程与线程的预热篇
,接下来的文章会 对 Node.js 的进程与线程做一个详细讲解,包括原理分析,child_process 模块与 cluse r模块,进程守护以及在真实项目中的 Node.js 多进程架构模型。
公众号:程序员成长指北(ID:coder_growth)
作者:koala 专注完整的 Node.js 技术栈分享,从 JavaScript 到 Node.js,再到后端数据库,祝您成为优秀的高级 Node.js 工程师
文章同步到github博客:https://github.com/koala-coding/goodBlog