1. 程式人生 > >nodejs的事件驅動模型

nodejs的事件驅動模型

Node.Js是基於javascript語言,建構在google V8 engine以及Linux上的一個非阻塞事件驅動IO框架。nodejs是單程序單執行緒,但是基於V8的強大驅動力,以及事件驅動模型,nodejs的效能非常高,而且想達到多核或者多程序也不是很難(現在已經有大量的第三方module來實現這個功能)。

這裡介紹一下事件驅動程式設計。
以下兩種典型的事件驅動例項。
第一個例子是關於醫生看病。

在美國去看醫生,需要填寫大量表格,比如保險、個人資訊之類,傳統的基於執行緒的系統(thread-based system),接待員叫到你,你需要在前臺填寫完成這些表格,你站著填單,而接待員坐著看你填單。你讓接待員沒辦法接待下一個客戶,除非完成你的業務。

想讓這個系統能執行的快一些,只有多加幾個接待員,人力成本需要增加不少。

基於事件的系統(event-based system)中,當你到視窗發現需要填寫一些額外的表格而不僅僅是掛個號,接待員把表格和筆給你,告訴你可以找個座位填寫,填完了以後再回去找他。你回去坐著填表,而接待員開始接待下一個客戶。你沒有阻塞接待員的服務。

你填完表格,返回隊伍中,等接待員接待完現在的客戶,你把表格遞給他。如果有什麼問題或者需要填寫額外的表格,他給你一份新的,然後重複這個過程。

這個系統已經非常高效了,幾乎大部分醫生都是這麼做的。如果等待的人太多,可以加入額外的接待員進行服務,但是肯定要比基於執行緒模式的少得多。

第二個例子是快餐店點餐。

在基於執行緒的方式中(thread-based way)你到了櫃檯前,把你的點餐單給收銀員或者給收銀員直接點餐,然後等在那直到你要的食物準備好給你。收銀員不能接待下一個人,除非你拿到食物離開。想接待更多的客戶,容易!加更多的收銀員!

當然,我們知道快餐店其實不是這樣工作的。他們其實就是基於事件驅動方式,這樣收銀員更高效。只要你把點餐單給收銀員,某個人已經開始準備你的食物,而同時收銀員在進行收款,當你付完錢,你就站在一邊而收銀員已經開始接待下一個客戶。在一些餐館,甚至會給你一個號碼,如果你的食物準備好了,就呼叫你的號碼讓你去櫃檯取。關鍵的一點是,你沒有阻塞下一個客戶的訂餐請求。你訂餐的食物做好的事件會導致某個人做某個動作(某個服務員喊你的訂單號碼,你聽到你的號碼被喊到去取食物),在程式設計領域,我們稱這個為回撥(callback function)。

Node.Js做了什麼工作呢?

傳統的web server多為基於執行緒模型。你啟動Apache或者什麼server,它開始等待接受連線。當收到一個連線,server保持連線連通直到頁面或者什麼事務請求完成。如果他需要花幾微妙時間去讀取磁碟或者訪問資料庫,web server就阻塞了IO操作(這也被稱之為阻塞式IO).想提高這樣的web server的效能就只有啟動更多的server例項。

相反的,Node.Js使用事件驅動模型,當web server接收到請求,就把它關閉然後進行處理,然後去服務下一個web請求。當這個請求完成,它被放回處理佇列,當到達佇列開頭,這個結果被返回給使用者。這個模型非常高效可擴充套件性非常強,因為webserver一直接受請求而不等待任何讀寫操作。(這也被稱之為非阻塞式IO或者事件驅動IO)

考慮下面這個過程:

1,你用瀏覽器訪問nodejs伺服器上的”/about.html”

2,nodejs伺服器接收到你的請求,呼叫一個函式從磁碟上讀取這個檔案。

3,這段時間,nodejs webserver在服務後續的web請求。

4,當檔案讀取完畢,有一個回撥函式被插入到nodejs的服務佇列中。

5,nodejs webserver執行這個函式,實際上就是渲染(render)了about.html頁面返回給你的瀏覽器。

好像就節省了幾微秒時間,但是這很重要!特別是對於需要相應大量使用者的web server。

這也就是為什麼Node.Js這麼熱這麼惹人關注。而且它還使用了一個非常通用的程式語言Javascript,也讓開發者可以快速容易的編寫高可擴充套件性伺服器。