久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      深入聊聊Node 異步和事件循環(huán)的底層實(shí)現(xiàn)和執(zhí)行機(jī)制

      深入聊聊Node 異步和事件循環(huán)的底層實(shí)現(xiàn)和執(zhí)行機(jī)制

      Node 最初是為打造高性能的 Web 服務(wù)器而生,作為 JavaScript 的服務(wù)端運(yùn)行時(shí),具有事件驅(qū)動(dòng)、異步 I/O、單線程等特性?;谑录h(huán)的異步編程模型使 Node 具備處理高并發(fā)的能力,極大地提升服務(wù)器的性能,同時(shí),由于保持了 JavaScript 單線程的特點(diǎn),Node 不需要處理多線程下狀態(tài)同步、死鎖等問題,也沒有線程上下文切換所帶來的性能上的開銷?;谶@些特性,使 Node 具備高性能、高并發(fā)的先天優(yōu)勢(shì),并可基于它構(gòu)建各種高速、可伸縮網(wǎng)絡(luò)應(yīng)用平臺(tái)。

      本文將深入 Node 異步和事件循環(huán)的底層實(shí)現(xiàn)和執(zhí)行機(jī)制,希望對(duì)你有所幫助。

      為什么要異步?

      Node 為什么要使用異步來作為核心編程模型呢?

      前面說過,Node 最初是為打造高性能的 Web 服務(wù)器而生,假設(shè)業(yè)務(wù)場(chǎng)景中有幾組互不相關(guān)的任務(wù)要完成,現(xiàn)代主流的解決方式有以下兩種:

      • 單線程串行依次執(zhí)行。

      • 多線程并行完成。

      單線程串行依次執(zhí)行,是一種同步的編程模型,它雖然比較符合程序員按順序思考的思維方式,易寫出更順手的代碼,但由于是同步執(zhí)行 I/O,同一時(shí)刻只能處理單個(gè)請(qǐng)求,會(huì)導(dǎo)致服務(wù)器響應(yīng)速度較慢,無法在高并發(fā)的應(yīng)用場(chǎng)景下適用,且由于是阻塞 I/O,CPU 會(huì)一直等待 I/O 完成,無法做其他事情,使 CPU 的處理能力得不到充分利用,最終導(dǎo)致效率的低下,

      而多線程的編程模型也會(huì)因?yàn)榫幊讨械臓顟B(tài)同步、死鎖等問題讓開發(fā)人員頭疼。盡管多線程在多核 CPU 上能夠有效提升 CPU 的利用率。

      雖然單線程串行依次執(zhí)行和多線程并行完成的編程模型有其自身的優(yōu)勢(shì),但是在性能、開發(fā)難度等方面也有不足之處。

      除此之外,從響應(yīng)客戶端請(qǐng)求的速度出發(fā),如果客戶端同時(shí)獲取兩個(gè)資源,同步方式的響應(yīng)速度會(huì)是兩個(gè)資源的響應(yīng)速度之和,而異步方式的響應(yīng)速度會(huì)是兩者中最大的一個(gè),性能優(yōu)勢(shì)相比同步十分明顯。隨著應(yīng)用復(fù)雜度的增加,該場(chǎng)景會(huì)演變成同時(shí)響應(yīng) n 個(gè)請(qǐng)求,異步相比于同步的優(yōu)勢(shì)將會(huì)凸顯出來。

      綜上所述,Node 給出了它的答案:利用單線程,遠(yuǎn)離多線程死鎖、狀態(tài)同步等問題;利用異步 I/O,讓單線程遠(yuǎn)離阻塞,以更好地使用 CPU。這就是 Node 使用異步作為核心編程模型的原因。

      此外,為了彌補(bǔ)單線程無法利用多核 CPU 的缺點(diǎn),Node 也提供了類似瀏覽器中 Web Workers 的子進(jìn)程,該子進(jìn)程可以通過工作進(jìn)程高效地利用 CPU。

      如何實(shí)現(xiàn)異步?

      聊完了為什么要使用異步,那要如何實(shí)現(xiàn)異步呢?

      我們通常所說的異步操作總共有兩類:一是像文件 I/O、網(wǎng)絡(luò) I/O 這類與 I/O 有關(guān)的操作;二是像 setTimeOut、setInterval 這類與 I/O 無關(guān)的操作。很明顯我們所討論的異步是指與 I/O 有關(guān)的操作,即異步 I/O。

      異步 I/O 的提出是期望 I/O 的調(diào)用不會(huì)阻塞后續(xù)程序的執(zhí)行,將原有等待 I/O 完成的這段時(shí)間分配給其余需要的業(yè)務(wù)去執(zhí)行。要達(dá)到這個(gè)目的,就需要用到非阻塞 I/O。

      阻塞 I/O 是 CPU 在發(fā)起 I/O 調(diào)用后,會(huì)一直阻塞,等待 I/O 完成。知道了阻塞 I/O,非阻塞 I/O 就很好理解了,CPU 在發(fā)起 I/O 調(diào)用后會(huì)立即返回,而不是阻塞等待,在 I/O 完成之前,CPU 可以處理其他事務(wù)。顯然,相比于阻塞 I/O,非阻塞 I/O 多于性能的提升是很明顯的。

      那么,既然使用了非阻塞 I/O,CPU 在發(fā)起 I/O 調(diào)用后可以立即返回,那它是如何知道 I/O 完成的呢?答案是輪詢。

      為了及時(shí)獲取 I/O 調(diào)用的狀態(tài),CPU 會(huì)不斷重復(fù)調(diào)用 I/O 操作來確認(rèn) I/O 是否已經(jīng)完成,這種重復(fù)調(diào)用判斷操作是否完成的技術(shù)就叫做輪詢。

      顯然,輪詢會(huì)讓 CPU 不斷重復(fù)地執(zhí)行狀態(tài)判斷,是對(duì) CPU 資源的浪費(fèi)。并且,輪詢的間間隔很難控制,如果間隔太長(zhǎng),I/O 操作的完成得不到及時(shí)的響應(yīng),間接降低應(yīng)用程序的響應(yīng)速度;如果間隔太短,難免會(huì)讓 CPU 花在輪詢的耗時(shí)變長(zhǎng),降低 CPU 資源的利用率。

      因此,輪詢雖然滿足了非阻塞 I/O 不會(huì)阻塞后續(xù)程序的執(zhí)行的要求,但是對(duì)于應(yīng)用程序而言,它仍然只能算是一種同步,因?yàn)閼?yīng)用程序仍然需要等待 I/O 完全返回,依舊花費(fèi)了很多時(shí)間來等待。

      我們所期望的完美的異步 I/O,應(yīng)該是應(yīng)用程序發(fā)起非阻塞調(diào)用,無須通過輪詢的方式不斷查詢 I/O 調(diào)用的狀態(tài),而是可以直接處理下一個(gè)任務(wù),在 I/O 完成后通過信號(hào)量或回調(diào)將數(shù)據(jù)傳遞給應(yīng)用程序即可。

      如何實(shí)現(xiàn)這種異步 I/O 呢?答案是線程池。

      雖然本文一直提到,Node 是單線程執(zhí)行的,但此處的單線程是指 JavaScript 代碼是執(zhí)行在單線程上的,對(duì)于 I/O 操作這類與主業(yè)務(wù)邏輯無關(guān)的部分,通過運(yùn)行在其他線程的方式實(shí)現(xiàn),并不會(huì)影響或阻塞主線程的運(yùn)行,反而可以提高主線程的執(zhí)行效率,實(shí)現(xiàn)異步 I/O。

      通過線程池,讓主線程僅進(jìn)行 I/O 的調(diào)用,讓其他多個(gè)線程進(jìn)行阻塞 I/O 或者非阻塞 I/O 加輪詢技術(shù)完成數(shù)據(jù)獲取,再通過線程之間的通信將 I/O 得到的數(shù)據(jù)進(jìn)行傳遞,這就輕松實(shí)現(xiàn)了異步 I/O:

      深入聊聊Node 異步和事件循環(huán)的底層實(shí)現(xiàn)和執(zhí)行機(jī)制

      主線程進(jìn)行 I/O 調(diào)用,而線程池進(jìn)行 I/O 操作,完成數(shù)據(jù)的獲取,然后通過線程之間的通信將數(shù)據(jù)傳遞給主線程,即可完成一次 I/O 的調(diào)用,主線程再利用回調(diào)函數(shù),將數(shù)據(jù)暴露給用戶,用戶再利用這些數(shù)據(jù)來完成業(yè)務(wù)邏輯層面的操作,這就是 Node 中一次完整的異步 I/O 流程。而對(duì)于用戶來說,不必在意底層這些繁瑣的實(shí)現(xiàn)細(xì)節(jié),只需要調(diào)用 Node 封裝好的異步 API,并傳入處理業(yè)務(wù)邏輯的回調(diào)函數(shù)即可,如下所示:

      const fs = require("fs");  fs.readFile('example.js', (data) => {   // 進(jìn)行業(yè)務(wù)邏輯的處理 });

      Nodejs 的異步底層實(shí)現(xiàn)機(jī)制在不同平臺(tái)下有所不同:Windows 下主要通過 IOCP 來向系統(tǒng)內(nèi)核發(fā)送 I/O 調(diào)用和從內(nèi)核獲取已完成的 I/O 操作,配以事件循環(huán),以此完成異步 I/O 的過程;Linux 下通過 epoll 實(shí)現(xiàn)這個(gè)過程;FreeBSD下通過 kqueue 實(shí)現(xiàn),Solaris 下通過 Event ports 實(shí)現(xiàn)。線程池在 Windows 下由內(nèi)核(IOCP)直接提供,*nix 系列則由 libuv 自行實(shí)現(xiàn)。

      由于 Windows 平臺(tái)和 *nix 平臺(tái)的差異,Node 提供了 libuv 作為抽象封裝層,使得所有平臺(tái)兼容性的判斷都由這一層來完成,保證上層的 Node 與下層的自定義線程池及 IOCP 之間各自獨(dú)立。Node 在編譯期間會(huì)判斷平臺(tái)條件,選擇性編譯 unix 目錄或是 win 目錄下的源文件到目標(biāo)程序中:

      深入聊聊Node 異步和事件循環(huán)的底層實(shí)現(xiàn)和執(zhí)行機(jī)制

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)