<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] # 異步式I/O與事件式編程 Node.js最大的特點是異步式I/O(非阻塞I/O)與事件緊密結合的編程模式,此模式與傳統同步式I/O線性的編程思維不同,因為控制流很大程度要依靠事件和回調函數來組織,一個邏輯要拆分為若干單元。 <br> # 阻塞與線程 什么是阻塞(block)呢?線程在執行中若遇到磁盤讀寫或網絡通信(統稱為I/O操作),通常要耗費較長的時間,此時操作系統會剝奪這個線程的CPU控制權,使其暫停執行,同時將資源讓渡給其他工作線程,這種線程調度的方式稱為阻塞。 當I/O操作完畢后,操作系統將這個線程的阻塞狀態解除,恢復其對CPU的控制權,令其繼續執行。這種I/O模式即傳統的同步式I/O(Synchronous I/O)或阻塞式I/O(Blocking I/O)。 <br> 異步式I/O(Asynchronous I/O)或非阻塞式I/O(Non-blocking I/O)則針對所有I/O操作不采用阻塞的策略。當線程遇到I/O操作時,不會阻塞的方式等待I/O操作的完成或數據的返回,而只是將I/O請求發送給操作系統,繼續執行下一條語句。當操作系統完成I/O操作時,以事件的形式通知執行I/O操作的線程,線程會在特定時候處理這個事件。為了處理異步I/O,線程必須有事件循環,不斷地檢查有沒有未處理的事件,依次予以處理。 <br> 阻塞模式下,一個線程只能處理一項任務,要想提高吞吐量必須通過多線程。而非阻塞模式下,一個線程永遠在執行計算操作,這個線程所使用的CPU核心利用率永遠是100%,I/O以事件的方式通知。 <br> 在阻塞模式下,多線程往往能提高系統吞吐量,因為一個線程阻塞時還有其他線程在工作,多線程可讓CPU資源不被阻塞中的線程浪費。而在非阻塞模式下,線程不會被I/O阻塞,永遠在利用CPU。多線程帶來的好處僅僅是在多核CPU的情況下利用更多的核,而Node.js的單線程也能帶來同樣的好處。這就是為什么Node.js使用單線、非阻塞的事件編程模型。 <br> ![](https://box.kancloud.cn/8fbe2fd829ccf93a964517fd40b45936_765x766.png) 多線程同步式I/O <br> ![](https://box.kancloud.cn/ed790147ad1ff5983cae0b9cbf1a8be0_639x876.png) 單線程異步式I/O <br> 單線程事件驅動的異步式I/O比傳統的多線程阻塞式I/O好在哪里呢?簡而言之,異步式I/O就是少了多線程的開銷。對操作系統來說,創建一個線程的代價是十分昂貴的,需要給它分配內存、列入調度,同時在線程切換時還需執行內存換頁,CPU的緩存被清空,切換回來時還要重新從內存中讀取數據,破壞了數據的局部性。 ![](https://box.kancloud.cn/ab198635cdae5517a11fe7a0ada4d030_1000x291.png) <br> # 事件循環機制 Node.js在什么時候會進入事件循環呢?Node.js程序由事件循環開始到事件循環結束,所有的邏輯都是事件的回調函數,所以Node.js始終在事件循環中,程序入口就是事件循環第一個事件的回調函數。事件的回調函數在執行過程中,可能會發出I/O請求或直接發射(emit)事件,執行完畢后再返回事件循環,事件循環會檢查事件隊列中有沒有未處理的事件,直至程序結束。 <br> ![](https://box.kancloud.cn/72aacea80eaed32da2d7e0600797bdb5_749x862.png) 事件循環機制 <br> Node.js沒有顯式的事件循環,它對開發者不可見,由libev庫實現。libev支持多種類型的事件,如ev_io、ev_timer、ev_signal、ev_idle等,在Node.js中均被EventEmitter封裝。libev事件循環的每一次迭代,在Node.js中就是一次Tick,libev不斷檢查是否有活動的、可供檢測的事件監聽器,直至檢測不到時才退出事件循環,進程結束。 <br> # 單線程 Node.js保持了JS在瀏覽器中單線程的特點,在Node中JS與其余線程是無法共享任何狀態的。單線程最大好處是不用像多線程編程那樣處處在意狀態的同步問題,這里沒有死鎖的存在,也沒有線程上下文交換帶來的性能上的開銷。 <br> 同樣,單線程也有自身的弱點,具體表現在 * 無法利用多核CPU * 錯誤會引起整個應用退出,應用的健壯性值得考驗。 * 大量計算占用CPU導致無法繼續調用異步I/O <br> 像瀏覽器中的JS與UI公用一個線程一樣,JS長時間執行會導致UI的渲染和響應被中斷。在Node中,長時間的CPU占用也會導致后續的異步I/O發不出調用,已完成的異步I/O的回調函數也會得不到及時執行。 最早解決這種大計算問題的方案是Google公司開發的Gears,它啟用了一個完全能獨立的進程,將需要計算的程序發送給這個進程,在結果得出后,通過事件將結果傳遞回來。這個模型將計算分發到其他進程上,以次來降低運算造成阻塞的幾率。 <br> 后臺H5制定了Web Workers的標準,Google放棄了Gears,全力支持Web Workers。Web Workers能夠創建工作線程來進行計算,以解決JS大計算阻塞UI渲染的問題。工作線程為了不阻塞主線程,通過消息傳遞的方式來傳遞運行結果,這也使得工作進程不能訪問主線程中的UI。 <br> Node采用了與Web Workers相同的思路來解決單線程中大量計算的問題(child_process)。子進程的出現,意味著Node可從容地應對單線程在健壯性和無法利用多核CPU方面的問題。通過將計算分發到各個子進程,可將大量計算分解掉,然后在通過進程之間的事件消息來傳遞結果,這可以很好地保持應用模型的簡單和低依賴。通過Master-Worker的管理方式,也可很好地管理各個工作進程,以達到更高的健壯性。 關于如何通過子進程來充分利用硬件資源和提升應用的健壯性,這是一個值得探究的話題。 <br> <br> # 事件驅動模型 沒有多線程額外工作,性能較高 每一個API都是異步執行,作為獨立線程 ![](https://box.kancloud.cn/fc292fc53227c39e50f5786a947e88b7_1632x884.png) <br> <br> # 事件處理流程 1. 引入event對象,創建eventEmitter對象 2. 綁定事件處理程序 3. 觸發事件 ``` // 引入event對象,創建eventEmitter對象 var events = require('events') var eventEmitter = new events.EventEmitter() var connectHandler = function () { console.log('connected') } // 綁定事件處理程序 eventEmitter.on('connection', connectHandler ) // 觸發事件 eventEmitter.emit('connection') console.log('程序執行完畢') ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看