用戶體驗javascript
異步的概念首先在web2.0中火起來,是由於瀏覽器中的javascript在單線程上執行,html
並且它還與UI的渲染共用一個線程,這意味着javascript在執行的時候UI渲染和響應式處於停滯狀態的前端
若是腳本的執行時間超過100毫秒,用戶就會感到頁面卡頓,覺得網頁中止響應.java
若是網頁臨時須要獲取一個網絡資源,經過同步的方式獲取,那麼javascript則須要等待資源徹底node
從服務器端獲取後才能繼續執行,這期間UI將停頓,不響應用戶的交互行爲.web
而若是採用異步請求,在下載資源期間,javascript和UI的執行都不會處於等待狀態.編程
同理,前端經過異步能夠消除UI阻塞的現象,可是前端獲取資源的速度也取決於後端的響應速度windows
如今又一情景,前端箱後端請求兩個資源後端
假設獲取資源s1須要耗時n1 獲取資源s2須要耗時n2瀏覽器
若是採起同步的方式,代碼大體以下
getData(s1);//耗時n1
getData(s2);//耗時n2
那麼總耗時即爲n1 + n2
若是採用異步的方式
getData(s1, function(result){
//耗時n1
});
getData(s2, function(result){
//耗時n2
});
那麼總耗時即爲max(n1, n2)
隨着應用複雜性的總消耗,情景將會變成n1 + n2 + n3 + ....和max(n1, n2, n3,......)
同步於異步的優點將會凸顯出來
另外一方面,隨着網站的或應用的不斷膨脹,
數據將會分佈到多臺服務器上,分佈式將會是常態
也就意味着n1,n2,n3...的值會線性增加,這也會方法異步和同步在性能方面的差別
下面列出從cpu一級緩存到網絡的數據訪問所須要的開銷
I/O類型 花費的CPU時鐘週期
cpu一級緩存 3
cpu二級緩存 14
內存 250
硬盤 41000000
網絡 240000000
資源分配
排除用戶體驗體驗的因素,咱們從資源分配的層面來分析一下異步I/O的必要性
假設業務場景中有一組互不相關的任務須要完成,,現行得主流方法有如下兩種
單線程串行依次執行
多線程並行完成
分別的優缺點
單線程
優勢:比較符合編程人員按順序思考的思惟方式,它依然是最主流的編程方式
缺點:性能問題突出,任意一個略慢的任務都會致使後續執行代碼被阻塞,
多線程
優勢:若是建立多線程的開銷小於並行執行,那麼多線程是首選的,
在多核cpu上可以有效提高cpu的利用率,這個優點毋庸置疑
缺點:建立線程和執行期線程上下文切換開銷較大,另外在稍複雜的業務中
還經常面臨鎖,狀態同步等問題,這是多線程被詬病的主要緣由
單線程同步編程模型會因阻塞I/O致使硬件資源得不到更優的使用,多線程編程模型也由於
編程中的死鎖,狀態同步等問題讓開發人員頭疼
node在二者之間給出了他的方案:利用單線程,遠離多線程死鎖,狀態同步等問題
利用異步I/O,讓單線程遠離阻塞,以更好地使用cpu
而且,爲了彌補單線程沒法利用多核cpu的缺點,node還提供了相似前端瀏覽器中的
Web Workers的子進程,該子進程能夠經過工做進程高效地利用CPU和I/O
異步I/O與非阻塞I/O
在node中,常常提早異步非阻塞I/O的概念,貌似異步與非阻塞彷佛是同一回事,
就實際效果而言,異步和非阻塞都達到了咱們並行I/O的目的,可是從計算機內核I/O而言
異步/同步 和 阻塞/非阻塞其實是兩回事
這裏因爲本人對系統底層的實現並不太瞭解,因此只能上網找了些資料
http://blog.csdn.net/historyasamirror/article/details/5778378
http://www.zhihu.com/question/19732473
http://www.cppblog.com/converse/archive/2009/05/13/82879.html
上面列舉一些可供參考的文章和知乎上的提問可供你們參考
我也暫時沒能力很好地爲異步/同步 和 阻塞/非阻塞的概念作解析,
node在*nix平臺下自行實現了線程池來完成異步I/O
在windows平臺下則採用了IOCP實現異步I/O
須要強調一點的是,這裏的I/O不只僅只限於磁盤文件的讀寫,*nix將計算機抽象了一番,
磁盤文件,硬件,套接字等幾乎全部計算機資源都被抽象爲了文件,所以阻塞和非阻塞的狀況一樣能適合套接字等
另外一個須要強調的地方在於咱們時常提到的node是單線程,這裏的單線程僅僅只是javascript執行在單線程中罷了
在node中,不管是*nix仍是windows平臺,內部完成I/O任務的另有線程池
node的異步I/O
首先,咱們着重強調一下node自身的執行模型-時間循環
正是它使得回調函數十分廣泛
但進程啓動是,node便會建立一個相似while(true)的循環
每執行一次循環體的過程咱們稱爲Tick,每一個Tick的過程就是查看是否有事件待處理,
若是有,就取出時間及其相關的回調函數,若是存在關聯的回調函數,就執行他們,而後進入下個循環
若是再也不有事件處理,就退出進程
每一個事件循環中有一個或者多個觀察這,而判斷是否有事件要處理的過程就是向這些觀察者詢問是否有要處理的事件
瀏覽器採用了相似的機制,時間可能來自用戶的點擊或者加載某些文件時產生,
而這些產生的事件都有其對應的觀察者,在node中,事件主要來源於網絡請求,文件I/O等,
這些事件對應的觀察者有文件I/O觀察者,網絡I/O觀察者等,觀察者將事件進行了分類.
時間循環是一個典型的生產者/消費者模型,異步I/O,網絡請求等則是事件的生產這,
源源不斷爲node提供不一樣類型的時間,這些事件被傳遞到對應的觀察者哪裏,事件循環則從觀察者那裏取出時間並處理
node中的單線程與I/O線程池之間看起來有些悖論的樣子,事實上,在node中,除了javascript是單線程的,
因此按常識很容易理解爲它不能充分利用多核cpu,事實上,在node中,除了javascript是單線程外,node自身實際上是多線程的
只是I/O線程使用的cpu較少,另外一個須要重視的觀點則是,除了用戶代碼沒法並行執行外,全部的I/O(磁盤I/O和網絡I/O)則是能夠
並行的,