nodejs v8引擎


Node.js 線程你理解的可能是錯的

本文代碼運行環境 系統:MacOS High Sierra Node.js:10.3.0 復制代碼

Node.js是單線程的,那么Node.js啟動后線程數是1?

答案:Node.js啟動后線程數並不是1,以下面代碼為例

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

通過Mac實用工具 > 活動監視器可以查看進程的線程數其實是6

Node.js啟動的線程數不為1,是因為線程池?

答案:線程數不為1,不是因為線程池,而是因為V8。Node.js啟動后會創建V8實例,V8實例是多線程的,V8中的線程有:

  • 主線程:獲取代碼、編譯執行
  • 編譯線程:主線程執行的時候,可以優化代碼
  • Profiler線程:記錄哪些方法耗時,為優化提供支持
  • 其他線程:用於垃圾回收清除工作,因為是多個線程,所以可以並行清除

Node.js線程池是預先創建好的?

答案:並不是,線程池中的線程是按需創建的。

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); }); 復制代碼

上面代碼啟動后,線程數依然是6

通過ab模擬訪問后

ab -n1000 -c20 'http://192.168.76.101:8000/' 復制代碼

線程數才變成了10。之所以為10,是因為線程池中線程的默認值是4。

異步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上有一個相關的提問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-APInode-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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM