閉包(closure)在非同步請求處理中有哪些優勢?
用C++寫同步請求處理和用C++寫非同步請求處理,兩者耗費的精力不可同日而與, 非同步處理需要很仔細的維護各種狀態,處理各種可能的衝突, 比同步處理難很多.
據說closure這個概念在非同步處理上很有幫助,但是我不會javascript或者其它支持closure的語言,只是感覺這個東西確實應該有幫助. 請各位指教.非同步請求一般都是靠業務相關的設置回調來完成,我在一份文檔中看到這麼一句話, 覺得很開眼界:
This is because specifying a method of an object as the callback function will cause the function by itself to be the callback, not the object associated with it.回調不僅保存了函數本身,也保存了環境,對於非同步處理來說,這真是一個很便利的好東西
Tim Caswell Why use "closure"? http://howtonode.org/why-use-closure
我倒認為耗費精力的大頭不在於是否有 closure。非同步 I/O 關鍵在於 completion callback。在 C/C++ 的非同步 I/O 中,一般發起 I/O 的函數會接受一個 userdata 參數,completion callback 會收到這個 userdata 參數。這個參數就是對 closure 的模擬。
第一,你需要手工定義所有需要 closed-over 的狀態為一個 struct,並且手工把當前的狀態保存到這個 struct 中。其實這步除了多打些字,很容易。第二,你要仔細設計內存和其它資源的管理。這才是難點。
所以,難點其實是 GC 一類和 closure 配套的特性。
C++ 有了 lambda,Mac 的 C 有 block。它們都是受限的 closure。受限的根本就是缺乏 GC。使用自動保存的作用域(scope)中被引用的變數來簡化回調函數的介面而已
禪宗曰,萬千大觀都只不過是,語法糖……
如果從狀態機的角度來理解閉包及提供閉包機制的虛擬機,任何外部模塊(比如HTTP傳輸模塊(IO線程)、Webkit渲染模塊(界面輸出)、瀏覽器界面(用戶輸入))輸入事件對回調函數的執行——觸動虛擬機的運行,從而改變狀態機的狀態,而再給外部模塊下出下一步動作指令——比如再發出一個AJAX請求,或者改變DOM讓渲染模塊工作等。
其實閉包或者提供閉包機制的腳本引擎,僅僅完成了對事件的響應,如果用C++來完成這一些任務,應該也不會很複雜。而真正複雜的地方在於外部模塊的特殊實現,比如傳輸模塊,它能夠接收發送數據請求、並在發送完成時,通知到虛擬機來執行相應的閉包,並且又能夠接收其它的請求,再請求完成時調用虛擬機的介面,完成閉包的執行。並且也有其它各種狀態變化發生時,通告虛擬機執行相應的閉包。如何將這些信號傳入到虛擬機之中,以及虛擬機發出的請求傳入給外部模塊,是必須解決的問題。當然信號傳入虛擬機,一般都是通過事件循環來進行的,原因是虛擬機通過會指導多個外部模塊,面這些模塊又不一定在同一個線程中執行。虛擬機本身成為了共享資源,多線程訪問時要麼加鎖,要麼使用事件隊列,虛擬機則從隊列中提取外部的處理請求,執行相關的閉包。
正是因為,虛擬機以及這模塊與虛擬機通訊的機制(事件循環)——通常都是相當複雜的,內存管理、狀態管理等高性能的無鎖事件隊列,從而大簡化了C++等Native模塊的開發呀。closure只是用來封裝callback的語法糖罷了,對解決反人類的非同步回調並沒有太多幫助。
真正解決這個問題的是,是非同步操作同步化,就是說,實際上是非同步的操作,然而使用者可以用同步的方式寫代碼,因為底層封裝了這些非同步操作的細節。
你可以看看Erlang就是這樣的。我也感覺是,但是感覺閉包回調什麼的和平常的思維不是很一樣啊,比較難適應。推薦你看node.js很容易學,不過不好做項目。
省得一個無比簡單的運算都要單獨寫個類封裝
C++ 11中增加了lambda 用以支援closure
------------
另外functor也可以很好的實現回調函數所需的功能,或者使用std::function and std::bind建議了解Promise 模式
推薦閱讀:
※如何用 TypeScript 提高 JS 工程的健壯性?
※ui-route實現頁面跳轉回來頁面不重新載入?
※如何評價 Node v6.0.0 (Current) ?
※一些網站能自動添加 URL 到 Safari 的閱讀列表,這是如何實現的?
※有哪些目前流行的前端框架?
TAG:JavaScript | Web伺服器軟體 | 非同步 | 閉包 |