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。api

異步IO都要佔用線程池?

答案:並非,網絡IO不會佔用線程池網絡

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壓測多線程

ab -n10000 -c20 'http://192.168.76.101:8000'

不管多少次訪問都不會建立線程,線程數永遠爲6。異步

文件IO必定會佔用線程池?

答案:並非,*Sync會阻塞主線程因此不會佔用線程池,另外fs.FSWatcher也不會佔用線程池。

雖然官方文檔裏面提到了fs.FSWatcher,可是其實並不能直接調用,關於FSWatcher訪問 StackOverflow上有一個相關的提問https://stackoverflow.com/questions/35115444/nodejs-fs-fswatcher

線程池只能用於異步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-j...

參考資料

https://nodejs.org/en/docs/gu...
https://medium.freecodecamp.o...
https://medium.com/the-node-j...
https://jsblog.insiderattack....

相關文章
相關標籤/搜索