這篇“Node中的異步實現與事件驅動方法是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Node中的異步實現與事件驅動方法是什么”文章吧。
創新互聯是一家專注于網站設計制作、成都網站建設與策劃設計,嵊泗網站建設哪家好?創新互聯做網站,專注于網站建設十年,網設計領域的專業建站公司;建站業務涵蓋:嵊泗等地區。嵊泗做網站價格咨詢:13518219792
計算機中的一些任務一般可以劃分為兩個類別,一個類別叫做IO密集型,一個叫做計算密集型;對于計算密集型的任務,只能不斷榨干CPU的性能,但是對于IO密集型的任務來說,理想情況下卻并不需要,只需要通知IO設備進行處理,過一段時間再來拿去數據就好了。
對于某些場景有一些互不相關的任務需要完成,現行的主流方法有如下兩種:
多線程并行完成:多線程的代價在于創建線程和執行線程上下文切換的開銷較大。另外,在復雜的業務中,多線程編程經常面臨鎖、狀態同步等問題;
單線程順序執行:易于表達,但串行執行的缺點在于性能,任意一個略慢的任務都會導致后續代碼被組設
node
在兩者之前給出了它的方案:利用單線程,遠離多線程死鎖、狀態同步等問題;利用異步IO,讓單線程遠離阻塞,以更好地使用CPU
剛才講了
node
在多任務處理的方案,但是node
內部想要實現卻并不容易,下面介紹操作系統的幾個概念,方面后續大家更好理解,后面再講一講異步的實現以及node的事件循環機制:
阻塞IO:應用層面發起IO調用之后,就一直等待數據,等操作系統內核層面完成所有操作后,調用才結束;
操作系統中一切皆文件,輸入輸出設備同樣被抽象為了文件,內核在執行IO操作時,通過文件描述符進行管理
非阻塞IO:差別為調用后立即返回一個文件描述符,并不等待,這時候CPU的時間片就可以用來處理其他事務,之后可以通過這個文件描述符進行結果的獲取;
非阻塞IO存在的一些問題:雖然其讓CPU的利用率提高了,但是由于立即返回的是一個文件描述符,我們并不知道IO操作什么時候完成,為了確認狀態變更,我們只能作輪詢操作
read
:最原始、性能最低的一種,通過重復檢查IO狀態來完成完整數據的獲取
select
:通過對文件描述符上的事件狀態來進行判斷,相對來說消耗更少;缺點就是它采用了一個1024長度的數組來存儲狀態,所以它最多可以同時檢查1024個文件描述符
poll
:由于select
的限制,poll
改進為鏈表的存儲方式,其他的基本都一致;但是當文件描述符較多的時候,它的性能還是非常低下的
eopll
:該方案是linux
下效率最高的IO事件通知機制,在進入輪詢的時候如果沒有檢查IO事件,將會進行休眠,直到事件發生將它喚醒
kqueue
:與epoll
類似,不過僅在FreeBSD系統下存在
盡管epoll
利用了事件來降低對CPU的耗用,但休眠期間CPU幾乎是閑置的;我們期待的異步IO應該是應用程序發起非阻塞調用,無須通過遍歷或事件喚醒等方式輪詢,可以直接處理下一個任務,只需IO完成后通過信號或者回調將數據傳遞給應用程序即可。
linux下還有中AIO方式就是通過信號或回調來傳遞數據的,不過只有Linux有,并且有限制無法利用系統緩存
先說結論,node
對異步IO的實現是通過多線程實現的??赡軙煜牡胤骄褪?code>node內部雖然是多線程的,但是我們程序員開發的JavaScript
代碼卻僅僅是運行在單線程上的。
node
通過部分線程進行阻塞IO或者非阻塞IO加上輪詢技術來完成數據獲取,讓一個線程進行計算處理,通過線程之間的通信將IO得到的數據進行傳遞,這就輕松實現了異步IO的模擬。
除了異步IO,計算機中的其他資源也適用,因為linux中一切皆文件,磁盤、硬件、套接字等幾乎所有計算機資源都被抽象為了文件,接下來介紹對計算機資源的調用都以IO為例子。
在進程啟動時,node
便會創建一個類似與while(true)
的循環,每執行一次循環體的過程我們成為Tick
;
簡單解釋一下:就是每次都從IO觀察者里面獲取執行完成的事件(是個請求對象,簡單理解就是包含了請求中產生的一些數據),然后沒有回調函數的話就繼續取出下一個事件(請求對象),有回調就執行回調函數
注:不同平臺有不同的細節實現,這張圖隱藏了相關平臺兼容細節,比如windows下使用IOCP中的
PostQueuedCompletionStatus()
提交執行狀態,通過GetQueuedCompletionStatus
獲取執行完成的請求,并且IOCP內部實現了線程池的細節,而linux等平臺通過eopll
實現這個過程,并在libuv
下自實現了線程池
setTimtout
與setInterval
除了IO等計算機資源需要異步調用之外,node
本身還存在一些與異步IO無關的一些其他異步API:
setTimeout
setInterval
setImmediate
process.nextTick
該小節先講解前面兩個api
它們的實現原理與異步IO比較類似,只是不需要IO線程池的參與:
setTimtout
與setInterval
創建的定時器會被插入到定時器觀察者內部的一個紅黑樹中
每次tick
執行的時候,會從該紅黑樹中迭代取出定時器對象,檢查是否超過定時時間
如果超過,就將這個事件(請求對象)推入到事件隊列中,在事件循環中執行其中的回調函數
紅黑樹:這里簡單提一下,就是一種特殊化的平衡二叉樹,可以自平衡,查找效率基本上就是該二叉樹的深度了O(log2n)
你有考慮過這個問題嗎,為什么定時器不需要線程池的參與了呢,如果你理解了之前章節對于異步IO實現原理的話,相信你應該能解釋出來,這里簡單說說原因來加深記憶:
node
中的IO線程池是用來調用IO并等待數據返回(看具體實現)的一種方式,它使JavaScript
單線程得以異步調用IO,并且不需要等待IO執行完成(因為是IO線程池做了),并且能獲取到最終的數據(通過觀察者模式:IO觀察者從線程池獲取執行完成的事件,事件循環機制執行后續的回調函數)
上述這段話可能有點簡略,如果你還不明白,可以看下之前的那幾種圖~
process.nextTick
與setImmediate
這兩個函數都是代表立即異步執行一個函數,那為什么不用setTimeout(() => { ... }, 0)
來完成呢?
定時器精度不夠
定時器使用紅黑樹來創建定時器對象和迭代操作,浪費性能
即process.nextTick
更加輕量
輕量具體來說:我們在每次調用process.nextTick
的時候,只會將回調函數放入隊列中,在下一輪Tick
時取出執行。定時器中采用紅黑樹的方式時O(log2n),nextTick
為O(1)
那process.nextTick
與setImmediate
又有什么區別呢?畢竟它們都是將回調函數立即異步執行
process.nextTick
的回調執行優先級高于setImmediate
process.nextTick
的回調函數保存在一個數組中,每輪事件循環下全部執行,setImmediate
的結果則是保存在鏈表中,每輪循環按序執行第一個回調
注意:之所以process.nextTick
的回調執行優先級高于setImmediate
,因為事件循環對觀察者的檢查是有順序的,process.nextTick
屬于idle
觀察者,setImmediate
屬于check
觀察者。iedl觀察者 > IO 觀察者 > check觀察者
對于網絡套接字的處理,
node
也應用到了異步IO,網絡套接字上偵聽到的請求都會形成事件交給IO觀察者,事件循環會不停地處理這些網絡IO事件,如果我們在JavaScrpt
層面上有傳入對應的回調函數,這些回調函數就會在事件循環中執行(處理這些網絡請求)
常見的服務器模型:
同步式
每進程-->每請求
每線程-->每請求
而node
采用的是事件驅動的方式處理這些請求,無需對每個請求創建額外的對應線程,可以省略掉創建線程和銷毀線程的開銷,同時操作系統的調度任務因為線程較少(只有node
內部實現的一些線程)上下文切換的代價很低。
經典問題--雪崩問題的解決:
問題描述:服務器在剛啟動時,緩存無數據,如果訪問量巨大,同一條SQL
會被發送到數據庫中反復查詢,影響性能。
解決方案:
const proxy = new events.EventEmitter();
let status = "ready"; // 狀態鎖,避免反復查詢
const select = function(callback) {
proxy.once("selected", callback); // 綁定一個只執行一次名為selected的事件
if(status === "ready") {
status = "pending";
// sql
db.select("SQL", (res) => {
proxy.emit("selected", res); // 觸發事件,返回查詢數據
status = "ready";
})
}
}
使用once
將所有請求的回調都壓入了事件隊列中,利用其只執行一次就會將監視器移除的特點,保證每一個回調函數只會被執行一次。對于相同的SQL語句,保證在同一個查詢開始到結束的過程中永遠只有一次。新到來的相同調用只需在隊列中等待數據就緒即可,一旦查詢到結果,得到的結果就可以被這些調用共同使用。
以上就是關于“Node中的異步實現與事件驅動方法是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注創新互聯行業資訊頻道。
網站題目:Node中的異步實現與事件驅動方法是什么
本文網址:http://m.newbst.com/article36/iigcpg.html
成都網站建設公司_創新互聯,為您提供網站收錄、關鍵詞優化、App設計、微信小程序、做網站、網站策劃
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯