事件處理模型, 也便是全異步事件處理模型。在之前, 對於那些同時執行多項任務, 但仍能響應用戶交互的應用程序一般須要實施一種使用多進程(如linux的fork操做)或者多線程的操做。對於低併發的環境, 這樣作無疑能避免進程因等待某個操做而出現"假死"現象。但對於更復雜的異步應用程序或者是要求高併發的環境, 就要使用事件模型來處理異步事件, 這樣作有不少好處:javascript
固然, 基於事件的處理模型也有其缺點:html
當前, 基於事件的處理模型被應用到了各類環境之中。譬如linux的epoll模塊, javascript語言以及Nginx服務器等。java
本文地址: http://www.cnblogs.com/blackmanba/p/3676636.html或者http://forkme.info/about-event-loop/, 轉載請註明源地址。linux
<script type="text/javascript"> var callback = function () { alert('Hello world'); }; doucment.onclick = callback; ...... </script>
這就是實現事件處理模型的通常模式: 首先定義一個或多個異步事件, 每個事件綁定回調函數。主進程註冊完事件後就繼續執行, 只有當事件被觸發時纔會執行回調函數。放到例子當中就是當用戶點擊文檔時會彈出窗口並顯示 Hello world。服務器
綜上: 基於事件模型的程序要具有如下結構, 如圖:多線程
Event Loop是一個很重要的概念, 指的是計算機系統實現的一種運行方式, 主要用於等待併發送消息和事件。雖然在每一種實現方式中具體的實現方法可能不一樣(例如Nginx事件模型和javascript事件模型), 可是都須要實現並維護Event Loop。
在計算機中, 每個運行的程序就叫作進程(process)。 通常狀況下, 一個進程只能一次只能執行一個任務。若是想要執行多個任務, 不外乎如下三種解決方式:併發
以上2和3方式分別對應多進程和多線程模型, 優劣在以前已經講述。而事件處理模型正是基於上面第一種方式, 這樣作能夠避免沒必要要的進程或線程間切換, 保證進程的高效運行。可是有一個問題, 一旦遇到大量任務或者是遇到一個耗時的操做, 進程就會被阻塞, 出現所謂的"假死"現象, 沒法響應其餘操做。異步
按照上面的運行模型, 若是某個任務很耗時,那麼進程的運行大概是這個樣子:async
上圖的綠色部分是程序運行時間, 紅色部分是等待時間。這個進程在大部分時間都在等待其餘操做, 這種運行方式稱爲"同步模式"(synchronous I/O)或"堵塞模式"(blocking I/O)。函數
若是採用多進程或者多線程, 極可能就是下面這種狀況:
上圖代表, 比起單進程, 多進程耗費成倍的系統資源並閒置等待, 這顯然不合理。
Event Loop就是爲了解決單進程阻塞問題而提出來的一種合理方案。以javascript做爲例子, 在程序中設置一個主進程和若干個子線程(以1個子線程爲例)。主進程負責程序自己的運行並處理"非阻塞"操做; 子線程負責與其餘進程(主要是I/O操做等耗時進程)的通訊, 這個線程就被稱爲"Event Loop線程"。
上圖橙色表示空閒時間。每當遇到I/O操做等耗時操做時, 主進程就讓Event Loop線程去通知相應的I/O程序並註冊相應的事件和設置回調函數, 而後主線程接着日後運行, 因此不出現紅色的阻塞時間, 等到I/O操做完成, Event Loop線程再把結果返回主進程, 主進程調用實現設定的回調函數完成任務(注意: 回調函數不能執行太多的耗時操做, 由於此時主進程是處於阻塞狀態的)。這種運行方式稱爲"異步模式"(asynchronous I/O)或"非堵塞模式"(non-blocking mode)。這也是事件處理模型的內部實現機制。
在計算機中, 上下文表明着不少種含義。在基於事件的模型中,上下文表示什麼?簡單的講, 以javascript爲例, 就是在主進程註冊事件後將回調函數做用域內的變量保存成一個對象保存起來, 這個對象就叫作上下文對象。每個事件的回調函數都包含着本身的上下文對象, 當對應事件被調用並執行回調函數時, 函數能夠直接經過上下文對象得到做用域內保存變量的值, 這個操做對開發者是透明的, 開發着只須要直接寫對象名稱就能夠了。
在基於事件的模型中, 上下文是必須存在的, 爲何要定義上下文這個概念呢?由於基於事件的模型都是基於異步機制的。以javascript爲例, 每次主進程執行到結尾的時候就會釋放其做用域內的全部變量。換句話說, 無論事件有沒有被觸發, 主進程執行完全部的邏輯以後就會銷燬全部的變量。若是沒有上下文的話, 當用戶觸發事件執行回調函數時, 就會沒法找到其做用域內的變量, 使用上下文就是爲了讓每個特定的回調函數能訪問到屬於本身做用域內的變量的值。
在實現一個基於事件模型的應用的過程當中, 有一個問題是必須考慮到的, 那就是主進程究竟要建立多少子線程才比較合理, 也就是說Event Loop何時須要建立。若是建立的子線程太多或是太少, 會出現如下問題:
子線程的數目主要要根據應用處理的業務類型, 具體機器的內存和cpu等因素決定, 並無一致的規定。如下作法是比較好的一種實踐:
對於高併發, 多請求的事件, 傳統的多線程和多進程的方法已經難以應付這些狀況。而基於事件的模型因爲採用的是異步的方式, 經過相似於中斷上下文的操做, 能得到很好的併發性和高性能。而且能避免以前模型出現的一些棘手問題, 好比死鎖問題。隨着應用複雜度飛不斷提升, 相信會有更多的應用將會採用基於事件的模型來應對這些狀況。