做者:Nastassia Ovchinnikova翻譯:瘋狂的技術宅javascript
原文:https://flatlogic.com/blog/mu...前端
未經容許嚴禁轉載java
Node.js 是一個免費的跨平臺 JavaScript 運行時環境,儘管它本質上是單線程的,可是能夠在後臺使用多個線程來執行異步代碼。node
因爲 Node.js 的非阻塞性質,不一樣的線程執行不一樣的回調,這些回調首先委託給事件循環。 Node.js 運行時負責處理全部這一切。程序員
JavaScript 最初是做爲一種單線程編程語言構建的,僅在 Web 瀏覽器中運行。這意味着在一個過程當中,只有一組指令可以在給定的時間執行。web
僅在當前代碼塊的執行完成後,才移至下一個代碼塊。可是,JavaScript 的單線程性質使實現變得容易。面試
最初,JavaScript 對於僅用於向網站添加少許交互。因此並無對多線程的需求。可是時代已經變了,用戶要求也愈來愈高,JavaScript 已成爲「Web 上流行的編程語言」。編程
多線程如今變得很廣泛。因爲 JavaScript 是單線程語言,所以沒法在其中實現多線程。幸運的是,在這種狀況下,有一個很好的解決方法:Node.js。segmentfault
Node.js 框架並很多,這要歸功於 JavaScript 運行時環境(尤爲是 JavaScript)的廣泛流行。在繼續本文以前,讓咱們瞭解一些有關 Node.js 的重要觀點:後端
在兩種狀況下,咱們須要 fork 一個流程:
能夠將數據發送到子進程,也能夠將其送回。
Node.js 使用兩種類型的線程:
事件循環負責獲取回調或函數,並將其註冊以供未來執行。它與正確的 JavaScript 代碼在同一線程中運行。一旦 JavaScript 操做阻塞了線程,事件循環也會被阻塞。
工做池是一個執行模型,負責產生和處理不一樣的線程。它同步執行任務,而後將結果返回到事件循環,最後事件循環將結果提供給回調。
總而言之,工做池負責異步 I/O 操做,即與系統磁盤和網絡的交互。像 fs 和 crypto 這樣的模塊是使用工做池的主要模塊。
因爲工做池是在 libuv 庫中實現的,Node.js 在 JS 和 C++ 之間進行內部通訊時會稍有延遲。不過這幾乎是不可察覺的。
一切都很好,直到咱們遇到同步執行復雜操做的要求。任何須要大量時間執行的函數都會致使主線程阻塞。
若是程序具備多個佔用大量 CPU 的函數,將會致使服務器吞吐量的顯着降低。在最壞的狀況下,服務器將會失去響應,而且沒法將任務委派給工做池。
諸如 AI、大數據和機器學習之類的領域沒法從 Node.js 中受益,由於這些操做阻塞了主線程,並使服務器失去響應。可是這隨着 Node.js v10.5.0 的到來而改變,該版本增長了對多線程的支持。
在 JavaScript 中創建併發可能很困難。容許多個線程訪問相同的內存會致使競爭狀態,這不只使故障難以重現,並且解決起來也很困難。
Node.js 最初被實現爲基於異步 I/O 的服務器端平臺。經過簡單地消除線程需求,這使不少事情變得容易。是的,Node.js 程序是單線程的,但不是典型的方式。
咱們能夠在 Node.js 中並行運行,可是不須要建立線程。操做系統和虛擬機共同並行使用 I/O,而後在須要將數據發送回 JavaScript 代碼時,JS 代碼在單個線程中運行。
除 JS 代碼外,全部內容均在 Node.js 中並行運行。與異步塊不一樣,JS 的同步塊老是一次執行一次。與代碼執行相比,等待 JS 中產生 I/O 事件所話費的時間要多得多。
Node.js 程序僅調用所需的函數或回調,而不會阻止其餘代碼的執行。最初 JavaScript 和 Node.js 都不打算處理 CPU 密集型或 CPU 綁定的任務。
當代碼最少時,執行將會是敏捷的。可是計算量越大,執行速度就越慢。
若是你仍然嘗試在 JS 和 Node 中完成 CPU 密集型任務,那麼將會使瀏覽器中的 UI 凍結並對全部 I/O 事件進行排隊處理。儘管如此,咱們已經走了很遠。如今有了 worker_threads 模塊。
Node.js v10.5.0 於 2018 年 6 月發佈,引入了 worker_threads 模塊。它有助於在流行的 JavaScript 運行時環境中實現併發。該模塊容許建立功能齊全的多線程 Node.js 應用。
從技術上講,工做線程是在單獨的線程中產生的一些代碼。要開始使用輔助線程,須要先導入 worker_threads 模塊。以後須要建立 Worker 類的實例以建立工做線程。
建立 Worker 類的實例時,有兩個參數:
輔助線程可以調度多個消息事件。所以,回調方法優先於返回 promise。
工做線程之間的通訊是基於事件的,即偵聽器設置爲在工做線程發送事件後當即調用。最多見的 4 個事件是:
worker.on('error', (error) => {});
worker.on('exit', (exitCode) => {})
process.exit()
,則會將 exitCode 提供給回調。若是 worker.terminate()
終止工做線程,則代碼爲 1。worker.on('message', (data) => {});
worker.on('online', () => {});
有兩種使用工做線程的方法:
方法 2 也被稱爲工做池。這是由於該方法涉及建立 worker 的工做池,先讓他們等待,並在須要時去調度消息事件來執行任務。
因爲從頭建立工做線程須要建立虛擬機以及解析和執行代碼,所以官方 Node.js 文檔 建議採用方法 2。此外,方法 2 更爲實用,比方法 1 更有效。
爲了使 Node.js 利用多核系統的功能,能夠用一些進程。流行的 javascript 運行時環境中有稱被爲 cluster 的模塊,該模塊提供對多進程的支持。
使用 cluster 模塊能夠產生多個子進程,這些子進程能夠共享一個公共端口。當子進程投入使用時,使用 NodeJS 的系統能夠處理更大的工做量。
互聯網已經成爲全球數以百萬計公司的首選平臺。所以,爲使一家企業發揮最大潛力,並在此過程當中脫穎而出,必須擁有強大的網絡形象。
這一切都始於一個強大而直觀的網站。要打造一個完美無瑕的網站,重要的是選擇最佳的前端和後端技術。儘管本質上是單線程的,但 Node.js 是開發後端 Web 服務的首選。
儘管有大量的後端多線程選擇,但知名公司仍是喜歡 Node.js。這是由於 Node.js 提供了在 JavaScript 中使用多線程的變通方法,而 JavaScript 已是「Web上最流行的編程語言」。
worker_threads 模塊提供了一種在 Node.js 程序中實現多線程的簡便方法。經過將繁重的計算委派給工做線程,能夠顯着提升服務器的吞吐量。
藉助對多線程的支持,Node.js 將繼續吸引愈來愈多的來自 AI、大數據和機器學習等計算密集型領域的開發人員、工程師和其餘專業人員。