日期:2013年10月21日
[2014.10.08更新] 本文內容有錯誤驰怎,請參考新版本钞馁。
Event Loop 是一個很重要的概念虑省,指的是計算機系統(tǒng)的一種運行機制。
JavaScript語言就采用這種機制指攒,來解決單線程運行帶來的一些問題慷妙。
??????? 本文參考C. Aaron Cois的《Understanding The Node.js Event Loop》,解釋什么是Event Loop允悦,以及它與JavaScript語言的單線程模型有何關系膝擂。
想要理解Event Loop,就要從程序的運行模式講起隙弛。運行以后的程序叫做"進程"(process)架馋,一般情況下,一個進程一次只能執(zhí)行一個任務全闷。
如果有很多任務需要執(zhí)行叉寂,不外乎三種解決方法。
(1)排隊总珠。因為一個進程一次只能執(zhí)行一個任務屏鳍,只好等前面的任務執(zhí)行完了,再執(zhí)行后面的任務局服。
(2)新建進程钓瞭。使用fork命令,為每個任務新建一個進程淫奔。
(3)新建線程山涡。因為進程太耗費資源,所以如今的程序往往允許一個進程包含多個線程,由線程去完成任務鸭丛。(進程和線程的詳細解釋竞穷,請看這里。)
以JavaScript語言為例鳞溉,它是一種單線程語言瘾带,所有任務都在一個線程上完成,即采用上面的第一種方法穿挨。一旦遇到大量任務或者遇到一個耗時的任務月弛,網頁就會出現(xiàn)"假死",因為JavaScript停不下來科盛,也就無法響應用戶的行為。
你也許會問菜皂,JavaScript為什么是單線程贞绵,難道不能實現(xiàn)為多線程嗎?
這跟歷史有關系恍飘。JavaScript從誕生起就是單線程榨崩。原因大概是不想讓瀏覽器變得太復雜,因為多線程需要共享資源章母、且有可能修改彼此的運行結果母蛛,對于一種網頁腳本語言來說,這就太復雜了乳怎。后來就約定俗成彩郊,JavaScript為一種單線程語言。(WorkerAPI可以實現(xiàn)多線程蚪缀,但是JavaScript本身始終是單線程的秫逝。)如果某個任務很耗時,比如涉及很多I/O(輸入/輸出)操作询枚,那么線程的運行大概是下面的樣子违帆。
上圖的綠色部分是程序的運行時間,紅色部分是等待時間金蜀∷⒑螅可以看到,由于I/O操作很慢渊抄,所以這個線程的大部分運行時間都在空等I/O操作的返回結果尝胆。這種運行方式稱為"同步模式"(synchronous I/O)或"堵塞模式"(blocking I/O)。
如果采用多線程抒线,同時運行多個任務班巩,那很可能就是下面這樣。
上圖表明,多線程不僅占用多倍的系統(tǒng)資源抱慌,也閑置多倍的資源逊桦,這顯然不合理。
Event Loop就是為了解決這個問題而提出的抑进。Wikipedia這樣定義:
"Event Loop是一個程序結構强经,用于等待和發(fā)送消息和事件。(a programming construct that waits for and dispatches events or messages in a program.)"
簡單說寺渗,就是在程序中設置兩個線程:一個負責程序本身的運行匿情,稱為"主線程";另一個負責主線程與其他進程(主要是各種I/O操作)的通信信殊,被稱為"Event Loop線程"(可以譯為"消息線程")炬称。
????? 上圖主線程的綠色部分,還是表示運行時間涡拘,而橙色部分表示空閑時間玲躯。每當遇到I/O的時候,主線程就讓EventLoop線程去通知相應的I/O程序鳄乏,然后接著往后運行跷车,所以不存在紅色的等待時間。等到I/O程序完成操作橱野,EventLoop線程再把結果返回主線程朽缴。主線程就調用事先設定的回調函數,完成整個任務水援。
可以看到密强,由于多出了橙色的空閑時間,所以主線程得以運行更多的任務裹唆,這就提高了效率誓斥。這種運行方式稱為"異步模式"(asynchronous I/O)或"非堵塞模式"(non-blocking mode)。
這正是JavaScript語言的運行方式许帐。單線程模型雖然對JavaScript構成了很大的限制劳坑,但也因此使它具備了其他語言不具備的優(yōu)勢。如果部署得好成畦,JavaScript程序是不會出現(xiàn)堵塞的距芬,這就是為什么node.js平臺可以用很少的資源,應付大流量訪問的原因循帐。