【More Effective C#】區分早期執行和晚期執行
2010-10-20 08:19 空逸云 閱讀(2180) 評論(11) 收藏 舉報Lambda的出現.使我們除了可以使用"古老"的命令式代碼(imperative code),還可以使用聲明式代碼(declarative code),可以讓我們作出更為靈活的實現與工程實踐.
命令式代碼
顧名思義,命令式代碼如同發出命令般,一步一步地給出了完成指定工作需要的各個步驟.并且步驟是不可逆的.
object answer = DoSomeThing(Method1(), Method2(), Method3());
上面的代碼,在運行時,將按照如下的順序執行,
(1)調用Method1,生成DoSomeThing所需的第一個參數.
(2)調用Method2,生成DoSomeThing所需的第二個參數.
(3)調用Method3,生成DoSomeThing所需的第三個參數.
(4)使用調用得到的三個參數調用DoSomeThing,得到結果.
我們都應該很熟悉這種風格的代碼,必須先按部就班的計算出所需的參數,然后一次性傳遞給調用方法.該代碼包含了一系列描述步驟,遵循這種步驟才能得到我們所期待的結果.
注意:命令式模型做會調用所有的三個方法.三個方法中可能進行的額外操作也會且僅會發生一次.
聲明式代碼
聲明式代碼是解釋性的,它定義了將要完成什么工作.Lambda表達式所引入的延遲查詢,完全改變了原始代碼執行流程.例如,
object answer = DoSomeThing(() => Method1(), () => Method2(), () => Method3());
看起來和上面的例子并無多大區別,但是它們的執行順序卻全然不同.該代碼的執行順序如下
(1)調用DoSomeThing(),傳入可以調用Method1,Method2,Method3的Lambda表達式.
(2)在DoSomeThing中,僅在需要Method1的執行結果時,才會調用Method1.
(3)在DoSomeThing中,僅在需要Method2的執行結果時,才會調用Method2.
(4)在DoSomeThing中,僅在需要Method3的執行結果時,才會調用Method3.
(5)Method1,Method2,Method3可能會以任意的順序調用,并調用任意次(多次或零次)
注意:只有在需要某個方法的計算結果時,才會調用該方法.聲明式模型可能會也可能不會調用某個甚至所有方法,也可能多次執行同一個方法,所以,在多次運行同一個程序時,你可能將得到不同的結果.這取決于方法的具體實現.
實現的選擇
我們已經弄清楚了什么是早期執行,什么是延遲執行,除了執行順序的不同之外.它們還有什么區別?二者最主要的區別是,一個是準備數據,一個是準備方法.那么兩者之間該如何抉擇,什么時候該使用早期執行,什么時候該使用延遲執行.一個比較有效的建議是:
如果求值過程中不修改任何全局狀態(如全局變量等).那么我們可以使用延遲求值,否則,每次的調用我們都可能得不到預期的結果.再者,你需要獲取的數據是否不變的,如你的值是從緩存中獲取,那我們沒必要使用延遲求值,一句話,決定選擇早期求值和延遲求值的關鍵在于你想要實現的語義.
延遲求值的一個很好的例子是LINQ2SQl,若每次的求值都是早期執行,每次執行一條Lambda表達式將執行一次,服務器將多次繁忙的處理你這"一次"的請求,延遲求值直到需要所需的數據時才執行一次.大大的減輕了服務器的負擔.
更多的時候.我們編寫程序時,更應該考慮數據做為參數和方法作為參數兩者之間的權衡.所占用的空間不大,而傳入數據將更有優勢,相反,所數據輸出的空間可能會非常大,并且你不需要完整的數據.那采用方法參數則更勝一籌.若難以判斷與權衡.不妨試試對兩者不同應用場景的性能對比從而挑選出更適合的方式.
出處:http://kongyiyun.cnblogs.com
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
浙公網安備 33010602011771號