摘要:對于而言,單線程指的是它的執(zhí)行線程是單線程。對于來說,單線程不僅不是劣勢,它對于降低編程復(fù)雜度還有很重要的作用,單線程避免了多線程編程模型多線程死鎖狀態(tài)同步等問題。單線程的應(yīng)用是脆弱了,但群體的力量是強大的。
我們常聽說 JavaScript 是單線程的,那這個單線程是什么意思呢?單線程是否意味 JavaScript 存在性能缺陷呢?
在瀏覽器端,JavaScript 單線程指的是 JavaScript 的執(zhí)行線程與 UI 渲染線程共用一個線程。對于 NodeJS 而言,單線程指的是它的 JavaScript 執(zhí)行線程是單線程。雖然 JavaScript 只能單線程執(zhí)行,但 JavaScript 引擎可不是,它能夠創(chuàng)建多個線程為主線程服務(wù)。Web Worker 已經(jīng)得到大部分瀏覽器的支持,NodeJS 也擁有自己的線程池來處理 I/O 操作。無論前端還是后端,JavaScript 已經(jīng)能夠利用多個線程來提升程序性能了。
NodeJS 單線程異步 I/O 模型NodeJS 是單線程異步 I/O 模型。換句話說,NodeJS 代碼執(zhí)行占用一個線程,而代碼中的 I/O 操作則是交給其它線程執(zhí)行,執(zhí)行完畢后將結(jié)果交還給主線程。
對于 NodeJS 來說,單線程不僅不是劣勢,它對于降低編程復(fù)雜度還有很重要的作用,單線程避免了多線程編程模型多線程死鎖、狀態(tài)同步等問題。而異步 I/O 避免了單線程同步編程模型的阻塞問題,使 CPU 得到更充分的使用。
NodeJS 異步 I/O 模型的實現(xiàn)離不開 libuv 層,libuv 提供了一個線程池來執(zhí)行 I/O 操作,執(zhí)行完畢后再將結(jié)果返回給執(zhí)行線程,因此 I/O 操作不會阻塞執(zhí)行線程地繼續(xù)執(zhí)行。libuv 是一個事件驅(qū)動的異步 I/O 庫,它是跨平臺的,在 *nix 平臺下,自行實現(xiàn)了線程池,在 windows 平臺采用了 IOCP,IOCP 內(nèi)部仍是線程池原理,libuv 的線程池默認為 4 個線程。接下來我們在 Linux 環(huán)境下看一看 NodeJS 的多個線程。
查看 NodeJS 多線程首先,我們需要先編寫一個 js 腳本,寫入一個定時器使得腳本不會因為執(zhí)行完畢而被關(guān)掉。
setInterval(function () {}, 1000)
node命令執(zhí)行該腳本,開啟另一個窗口(或者把程序放后臺執(zhí)行)來查看 NodeJS 進程下的線程情況。
$ ps -a PID TTY TIME CMD 16699 pts/2 00:00:00 node 16706 pts/0 00:00:00 ps $ ps -L -p 16699 PID LWP TTY TIME CMD 16699 16699 pts/2 00:00:00 node 16699 16700 pts/2 00:00:00 V8 WorkerThread 16699 16701 pts/2 00:00:00 V8 WorkerThread 16699 16702 pts/2 00:00:00 V8 WorkerThread 16699 16703 pts/2 00:00:00 V8 WorkerThread 16699 16704 pts/2 00:00:00 node
可以看到包括 V8 引擎的工作線程在內(nèi),已經(jīng)開啟了 6 個線程(MAC OS 系統(tǒng)用ps -M -p
require("fs").readFile("test.js", function () {}) setInterval(function () {}, 1000)
重新啟動腳本,可以看到,啟動的 4 個新線程正是 libuv 線程池默認的 4 個線程。
$ ps -a PID TTY TIME CMD 16745 pts/2 00:00:00 node 16755 pts/0 00:00:00 ps $ ps -L -p 16745 PID LWP TTY TIME CMD 16745 16745 pts/2 00:00:00 node 16745 16746 pts/2 00:00:00 V8 WorkerThread 16745 16747 pts/2 00:00:00 V8 WorkerThread 16745 16748 pts/2 00:00:00 V8 WorkerThread 16745 16749 pts/2 00:00:00 V8 WorkerThread 16745 16750 pts/2 00:00:00 node 16745 16751 pts/2 00:00:00 node 16745 16752 pts/2 00:00:00 node 16745 16753 pts/2 00:00:00 node 16745 16754 pts/2 00:00:00 node
可以通過修改環(huán)境變量process.env.UV_THREADPOOL_SIZE(最大 128)使 NodeJS 支持更多地線程。
// js process.env.UV_THREADPOOL_SIZE = 64 require("fs").readFile("test.js", function () {}) setInterval(function () {}, 1000) // bash $ ps -a PID TTY TIME CMD 16782 pts/2 00:00:00 node 16852 pts/0 00:00:00 ps $ ps -L -p 16782 | wc -l 71
重新執(zhí)行腳本,可以看到減去第一行和 6 個初始線程,有 64 個線程在為 NodeJS 的異步 I/O 服務(wù)。
高并發(fā)和高可用JavaScript 是單線程,但 JavaScript 引擎能夠創(chuàng)建多個線程來服務(wù)與主線程,而 NodeJS 的主線程就像一個調(diào)度員,它能夠?qū)?I/O 操作,例如網(wǎng)絡(luò)請求,分發(fā)給其它線程進行處理,在通過事件機制將結(jié)果返回給主線程,因此,NodeJS 編寫的服務(wù)器能夠支持極大的并發(fā)量,這也是 NodeJS 的優(yōu)勢所在。NodeJS 主線程不宜進行大量地計算,因為這會阻塞主線程的運行。所以一般來說,NodeJS 適合 I/O 密集型場景,不適合 CPU 密集型場景。
除了多線程的支持,NodeJS 還提供 child_process 和 cluster 接口允許用戶創(chuàng)建很多子進程來處理任務(wù)。單線程的 NodeJS 應(yīng)用是脆弱了,但群體的力量是強大的。多進程、多線程的 NodeJS 才是服務(wù)器性能和穩(wěn)定性的保證。
參考資料http://docs.libuv.org/en/latest/threadpool.html
《深入淺出 NodeJS》
https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html
https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/85022.html
摘要:標準庫中的所有方法都提供非阻塞的異步版本,并接受回調(diào)函數(shù),某些方法還具有對應(yīng)的阻塞方法,其名稱以結(jié)尾。比較代碼阻塞方法同步執(zhí)行,非阻塞方法異步執(zhí)行。 阻塞與非阻塞概述 此概述介紹了Node.js中阻塞與非阻塞調(diào)用之間的區(qū)別,此概述將引用事件循環(huán)和libuv,但不需要事先了解這些主題,假設(shè)讀者對JavaScript語言和Node.js回調(diào)模式有基本的了解。 I/O主要指與libuv支持的...
摘要:異步編程在傳統(tǒng)編程實踐中,大多數(shù)操作都是同步發(fā)生的。中的異步編程異步是一種輸入輸出處理的形式,它允許在傳輸完成之前,其它處理能繼續(xù)進行。 本文轉(zhuǎn)載自:眾成翻譯譯者:網(wǎng)絡(luò)埋伏紀事鏈接:http://www.zcfy.cc/article/1759原文:https://blog.risingstack.com/node-hero-async-programming-in-node-js/ ...
摘要:單線程異步非阻塞然后,這又牽扯到了事件循環(huán)消息隊列,還有微任務(wù)宏任務(wù)這些。此步的位置不確定某個時刻后,定時器觸發(fā)線程通知事件觸發(fā)線程,事件觸發(fā)線程將回調(diào)函數(shù)加入消息隊列隊尾,等待引擎線程執(zhí)行。 前言 Philip Roberts 在演講 great talk at JSConf on the event loop 中說:要是用一句話來形容 JavaScript,我可能會這樣: Java...
摘要:一異步編程原理顯然,上面這種方式和銀行取號等待有些類似,只不過銀行取號我們并不知道上一個人需要多久才會完成。下面來探討下中的異步編程原理。 眾所周知,JavaScript 的執(zhí)行環(huán)境是單線程的,所謂的單線程就是一次只能完成一個任務(wù),其任務(wù)的調(diào)度方式就是排隊,這就和火車站洗手間門口的等待一樣,前面的那個人沒有搞定,你就只能站在后面排隊等著。在事件隊列中加一個延時,這樣的問題便可以得到緩解...
閱讀 3154·2021-11-22 13:54
閱讀 3443·2021-11-15 11:37
閱讀 3609·2021-10-14 09:43
閱讀 3506·2021-09-09 11:52
閱讀 3608·2019-08-30 15:53
閱讀 2467·2019-08-30 13:50
閱讀 2062·2019-08-30 11:07
閱讀 892·2019-08-29 16:32