站長資訊網
        最全最豐富的資訊網站

        如何理解 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 不完全是單線程程序。

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 中文成人无字幕乱码精品区| 国产精品无码无在线观看| 中文成人无字幕乱码精品区| 99亚洲精品视频| 国产精品丝袜黑色高跟鞋| 亚洲国产综合精品一区在线播放| 国产A√精品区二区三区四区| 久久精品www人人爽人人| 亚洲国产精品综合久久网络 | 久久99久久99小草精品免视看 | 91自慰精品亚洲| 91精品最新国内在线播放| 国产精品视频第一页| 亚洲а∨天堂久久精品| 国产精品午夜国产小视频| 国内精品免费在线观看| 国产精品无码A∨精品影院 | 国产一区二区三区精品视频| 欧美亚洲国产成人精品| 精品国产日产一区二区三区| 国产欧美日韩精品丝袜高跟鞋| 在线亚洲精品自拍| 无码精品人妻一区二区三区影院| 精品人妻V?出轨中文字幕| 国产精品igao视频| 99热都是精品久久久久久| 欧美精品亚洲精品日韩| 久久精品国产69国产精品亚洲| 2020久久精品国产免费| 97久久精品无码一区二区| 精品一区二区三区自拍图片区| 久久精品国产精品亚洲毛片 | 亚洲精品第一国产综合境外资源 | 国产欧美精品一区二区三区| 无码人妻精品一区二区三区东京热 | 嫩草伊人久久精品少妇AV| 青青青国产精品一区二区| 日本内射精品一区二区视频| 香蕉久久夜色精品升级完成 | 欧美日韩国产成人高清视频,欧美日韩在线精品一 | 国产叼嘿久久精品久久|