目錄
Node.js 是單線程的程式*
#同步方法,跑在main thread 裡面
非同步pbkdf2 方法,不跑在main thread 裡面
HTTP request
Event Loop
首頁 web前端 js教程 如何理解 Node.js 不是完全的單線程的程式(淺析)

如何理解 Node.js 不是完全的單線程的程式(淺析)

Feb 08, 2022 pm 06:20 PM
node.js 單執行緒

為什麼說 Node.js 不是完全的單執行緒?如何理解?以下這篇文章就來帶大家探討一下,希望對大家有幫助!

如何理解 Node.js 不是完全的單線程的程式(淺析)

相信大家都知道 node 是一個單執行緒程序,使用了 Event Loop 可以做到多並發。可惜這是不完全正確的。

那為什麼說 Node.js 不是完全的單執行緒的程式呢?

Node.js 是單線程的程式*

所有我們自己寫的Javsacript,V8, event loop都跑在同一個線程裡面,也就是main thrad 。

哎嗨,這不正說明 node 是單線程的嗎?

但也許你不知道 node 有很多模組背後都是 C code。

雖然 node 沒有給使用者暴露控制 thread 的權限,但是 C 是可以使用多執行緒的。

那麼什麼時候 node 會使用多執行緒呢?

  • 如果一個 node 方法,背後呼叫C 的同步方法,那麼都是跑在 main thread 裡面的。

  • 如果一個 node 方法,背後呼叫C 的非同步方法,有時候不是跑在 main thread 裡面的。

Talk is cheap, show me the code.

#同步方法,跑在main thread 裡面

#這裡crypto 相關模組,很多是C 寫的。下面一段程式是計算hash的函數,一般用來儲存密碼。

import { pbkdf2Sync } from "crypto";
const startTime = Date.now();
let index = 0;
for (index = 0; index < 3; index++) {
    pbkdf2Sync("secret", "salt", 100000, 64, "sha512");
    const endTime = Date.now();
    console.log(`${index} time, ${endTime - startTime}`);
}
const endTime = Date.now();
console.log(`in the end`);
登入後複製

輸出的時間,

0 time, 44 
1 time, 90
2 time, 134
in the end
登入後複製

可以看到每次大概都是花費~45ms,程式碼 main thread 上順序執行。

注意最後的輸出是誰? 注意這裡一次 hash 在我的 cpu 需要~45ms。

非同步pbkdf2 方法,不跑在main thread 裡面

import { cpus } from "os";
import { pbkdf2 } from "crypto";
console.log(cpus().length);
let startTime = console.time("time-main-end");
for (let index = 0; index < 4; index++) {
    startTime = console.time(`time-${index}`);
    pbkdf2("secret", `salt${index}`, 100000, 64, "sha512", (err, derivedKey) => {
        if (err) throw err;
        console.timeEnd(`time-${index}`);
    });
}
console.timeEnd("time-main-end");
登入後複製

輸出的時間,

time-main-end: 0.31ms
time-2: 45.646ms
time-0: 46.055ms
time-3: 46.846ms
time-1: 47.159ms
登入後複製

這裡看到,main thread 早早結束,然而每次計算的時間都是45ms,要知道一個cpu 計算hash 的時間是45ms,這裡node 絕對使用了多個線程進行hash計算。

如果我在這裡把呼叫次數改成10次,那麼時間如下,可以看到隨著CPU核數的用完,時間也在增加。再一次證明node 絕對使用了多個執行緒進行hash計算。

time-main-end: 0.451ms
time-1: 44.977ms
time-2: 46.069ms
time-3: 50.033ms
time-0: 51.381ms
time-5: 96.429ms // 注意这里,从第五次时间开始增加了
time-7: 101.61ms
time-4: 113.535ms
time-6: 121.429ms
time-9: 151.035ms
time-8: 152.585ms
登入後複製

雖然這裡證明了,node絕對啟用了多執行緒。但是有一點小小的問題?我的電腦的CPU是AMD R5-5600U,有6個核心12執行緒啊。但是為什麼時間是從第五次開始增加的呢,node沒有完全利用我的CPU啊?

原因是什麼呢?

Node 使用了預先定義的執行緒池,這個執行緒池的大小預設是4.

export UV_THREADPOOL_SIZE=6

讓我們在看一個例子,

HTTP request

import { request } from "https";
const options = {
  hostname: "www.baidu.com",
  port: 443,
  path: "/img/PC_7ac6a6d319ba4ae29b38e5e4280e9122.png",
  method: "GET",
};

let startTime = console.time(`main`);

for (let index = 0; index < 15; index++) {
  startTime = console.time(`time-${index}`);
  const req = request(options, (res) => {
    console.log(`statusCode: ${res.statusCode}`);
    console.timeEnd(`time-${index}`);
    res.on("data", (d) => {
      // process.stdout.write(d);
    });
  });

  req.on("error", (error) => {
    console.error(error);
  });

  req.end();
}

console.timeEnd("main");
登入後複製
main: 13.927ms
time-2: 83.247ms
time-4: 89.641ms
time-3: 91.497ms
time-12: 91.661ms
time-5: 94.677ms
.....
time-8: 134.026ms
time-1: 143.906ms
time-13: 140.914ms
time-10: 144.088ms
登入後複製

這裡主程式也早早結束了,這裡我啟動http request 去下載15次圖片,他們花費的時間並沒有成倍增加,似乎不受限於執行緒池/cpu的影響。

為什麼啊? ? Node 到底有沒有在使用線程池啊?

如果Node 背後的C 的異步方法,首先會嘗試是否有內核異步支持,例如這裡網絡請是使用epoll (Linux),如果內核沒有提供異步方式,Node才會使用自己的線程池。 。

所以 http 請求雖然是異步,不過是由核心實現的,等到核心完成後,會通知C , C 會通知給 main thread 處理callback。

那麼 Node 哪些非同步方法會使用執行緒池呢?哪些不會呢?

  • 原生Kernal Async

    • TCP/UDP server client
    • Unix Domain Sockets (IPC)
    • pipes
    • dns.resolveXXX
    • tty input(stdin etc)
    • #Unix signals
    • Child process
  • Thread pool

    • fs.*
    • dns.lookup
    • pipe (edge case)

這也是大部分Node 優化的切入點。

但是這些怎麼跟最重要的 Event Loop 結合起來呢?

Event Loop

相信大家都對 Event loop 非常熟悉了。 Event loop 好比一個分發員,

  • 如果是遇到普通 javascript 程式或 callback,交給 V8 處理。

  • 如果遇到同步方法後背是 C 寫的,交給C ,跑在 main thread。

  • 如果遇到非同步方法後背是 C 寫的,如果有核心非同步支持,從main thread 交給核心處理。

  • 如果是非同步方法後背是 C 寫的,如果沒有核心非同步支持,從 main thread 交給 thread pool。

  • thread pool 和核心有結果都會把結果回傳 event loop,如果註冊的有 javascript callback,就交給V8處理。

然後如此循環,直到沒有東西可以處理。

所以 Node 不完全是單執行緒程式。

更多node相關知識,請造訪:nodejs 教學

以上是如何理解 Node.js 不是完全的單線程的程式(淺析)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1668
14
CakePHP 教程
1428
52
Laravel 教程
1329
25
PHP教程
1273
29
C# 教程
1256
24
圖文詳解Node V8引擎的記憶體和GC 圖文詳解Node V8引擎的記憶體和GC Mar 29, 2023 pm 06:02 PM

這篇文章帶大家深入了解NodeJS V8引擎的記憶體和垃圾回收器(GC),希望對大家有幫助!

一文聊聊Node中的記憶體控制 一文聊聊Node中的記憶體控制 Apr 26, 2023 pm 05:37 PM

基於無阻塞、事件驅動建立的Node服務,具有記憶體消耗低的優點,非常適合處理海量的網路請求。在海量請求的前提下,就需要考慮「記憶體控制」的相關問題了。 1. V8的垃圾回收機制與記憶體限制 Js由垃圾回收機

聊聊如何選擇一個最好的Node.js Docker映像? 聊聊如何選擇一個最好的Node.js Docker映像? Dec 13, 2022 pm 08:00 PM

選擇一個Node的Docker映像看起來像是小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?

Node.js 19正式發布,聊聊它的 6 大功能! Node.js 19正式發布,聊聊它的 6 大功能! Nov 16, 2022 pm 08:34 PM

Node 19已正式發布,以下這篇文章就來帶大家詳解了解Node.js 19的 6 大特性,希望對大家有幫助!

聊聊用pkg將Node.js專案打包為執行檔的方法 聊聊用pkg將Node.js專案打包為執行檔的方法 Dec 02, 2022 pm 09:06 PM

如何用pkg打包nodejs可執行檔?以下這篇文章跟大家介紹一下使用pkg將Node專案打包為執行檔的方法,希望對大家有幫助!

深入聊聊Node中的File模組 深入聊聊Node中的File模組 Apr 24, 2023 pm 05:49 PM

文件模組是對底層文件操作的封裝,例如文件讀寫/打開關閉/刪除添加等等文件模組最大的特點就是所有的方法都提供的**同步**和**異步**兩個版本,具有sync 字尾的方法都是同步方法,沒有的都是異

一起聊聊Node中的事件循環 一起聊聊Node中的事件循環 Apr 11, 2023 pm 07:08 PM

事件循環是 Node.js 的基本組成部分,透過確保主執行緒不被阻塞來實現非同步編程,了解事件循環對建立高效應用程式至關重要。以下這篇文章就來帶大家深入了解Node中的事件循環 ,希望對大家有幫助!

node無法用npm指令怎麼辦 node無法用npm指令怎麼辦 Feb 08, 2023 am 10:09 AM

node無法用npm指令是因為沒有正確配置環境變量,其解決方法是:1、開啟“系統屬性”;2、找到“環境變數”->“系統變數”,然後編輯環境變數;3、找到nodejs所在的資料夾;4、點選「確定」即可。

See all articles