Node.js 线程你理解的多是错的

本文代码运行环境
系统:MacOS High Sierra
Node.js:10.3.0
复制代码

Node.js是单线程的,那么Node.js启动后线程数是1?

答案:Node.js启动后线程数并非1,如下面代码为例html

const http = require('http');

http.createServer((req, res) => {
    res.end('hello');
}).listen(8000, () => {
  console.log('server is listening: ' + 8000);
});
复制代码

经过Mac实用工具 > 活动监视器能够查看进程的线程数实际上是6node

Node.js启动的线程数不为1,是由于线程池?

答案:线程数不为1,不是由于线程池,而是由于V8。Node.js启动后会建立V8实例,V8实例是多线程的,V8中的线程有:git

  • 主线程:获取代码、编译执行
  • 编译线程:主线程执行的时候,能够优化代码
  • Profiler线程:记录哪些方法耗时,为优化提供支持
  • 其余线程:用于垃圾回收清除工做,由于是多个线程,因此能够并行清除

Node.js线程池是预先建立好的?

答案:并非,线程池中的线程是按需建立的。github

const http = require('http');
const fs = require('fs');

http.createServer((req, res) => {
  fs.readFile('./c.js', () => {});
  res.end('hello');
}).listen(8000, () => {
  console.log('server is listening: ' + 8000);
});
复制代码

上面代码启动后,线程数依然是6web

经过ab模拟访问后npm

ab -n1000 -c20 'http://192.168.76.101:8000/'
复制代码

线程数才变成了10。之因此为10,是由于线程池中线程的默认值是4。

异步IO都要占用线程池?

答案:并非,网络IO不会占用线程池api

const http = require('http');

http.createServer((req, res) => {
  http.get('http://192.168.1.100');
  res.end('hello');
}).listen(8000, () => {
  console.log('server is listening: ' + 8000);
});
复制代码

上面这段代码,使用ab压测bash

ab -n10000 -c20 'http://192.168.76.101:8000'
复制代码

不管多少次访问都不会建立线程,线程数永远为6。网络

文件IO必定会占用线程池?

答案:并非,*Sync会阻塞主线程因此不会占用线程池,另外fs.FSWatcher也不会占用线程池。多线程

虽然官方文档里面提到了fs.FSWatcher,可是其实并不能直接调用,关于FSWatcher访问 StackOverflow上有一个相关的提问stackoverflow.com/questions/3…

线程池只能用于异步IO?

答案:并非,除了一些IO密集操做外,Node.js对一些CPU密集的操做也会放到线程池里面执行(Crypto、Zlib模块)

DNS查询也有可能占用线程池?

答案:是的,由于dns.lookup方法会涉及到读取本地文件(例如nsswitch.conf,resolv.conf 以及 /etc/hosts)。而dns.resolve方法就不会占用线程池,这也是lookup和resolve的区别所在。

因此下面的代码,实际上是会占用线程池的,由于http.get在dns解析的时候默认使用的是lookup方法。

const http = require('http');

http.createServer((req, res) => {
  http.get('http://bj.meituan.com');
  res.end('hello');
}).listen(8000, () => {
  console.log('server is listening: ' + 8000);
});
复制代码

线程池只供Node.js核心模块内部使用?

答案:不是的,官方文档里面有以下描述

You can use the built-in Node Worker Pool by developing a C++ addon. On older versions of Node, build your C++ addon using NAN, and on newer versions use N-API. node-webworker-threads offers a JavaScript-only way to access Node's Worker Pool.

线程池内线程数能够为0吗,能够无限大吗?

答案:不能够为0,也不是无限大的。经过UV_THREADPOOL_SIZE能够修改线程池的线程数(默认为4),线程数最大值为128,最小值为1。

主线程任什么时候候都不会阻塞吗?

答案:不是的,主线程在特定的状况下是会阻塞的。Node.js的事件循环中有一个阶段是poll,poll阶段在特定状况下是会阻塞的。这就是下图服务启动起来没有任何用户请求的时候Event Loop执行一次的时间比有少许请求的时候还要长的缘由。

图片来源:https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c

参考资料

https://nodejs.org/en/docs/guides/dont-block-the-event-loop/ https://medium.freecodecamp.org/what-exactly-is-node-js-ae36e97449f5 https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c https://jsblog.insiderattack.net/event-loop-and-the-big-picture-nodejs-event-loop-part-1-1cb67a182810

相关文章
相关标签/搜索