目錄
lazy ideas:singleton
proxy:
Short-circuit evaluation:
generator:
函數(shù)式編程語(yǔ)言中的應(yīng)用:
cache:
Dirty Flag:
CopyOnWrite:
web開(kāi)發(fā)中的惰性加載與惰性預(yù)加載:
正文
lazy形容詞,懶惰的,毫無(wú)疑問(wèn)是一個(gè)貶義詞。但是,對(duì)于計(jì)算機(jī)領(lǐng)域,lazy卻是非常重要的優(yōu)化思想:把任務(wù)推遲到必須的時(shí)刻,好處是避免重復(fù)計(jì)算,甚至不計(jì)算。本文的目的是拋磚引玉,總結(jié)一些編程中的lazy idea,以期有一些啟發(fā)。google “l(fā)azy”這個(gè)單詞,在計(jì)算機(jī)領(lǐng)域高頻出現(xiàn)三個(gè)詞:lazy loading(惰性加載)、lazy initializing(惰性初始化)、lazy evaluation(惰性求值),本文并不刻意區(qū)分,因?yàn)椴还苁莑oading、initializing還是evaluation都需要耗費(fèi)計(jì)算機(jī)的運(yùn)算資源,而且,loading(initializing)也是某種意義上的evaluation。
lazy ideas:
回到頂部
在GOF的設(shè)計(jì)模式中,并沒(méi)有一個(gè)叫“l(fā)azy loading”之類的設(shè)計(jì)模式,但是其思想貫穿在很多設(shè)計(jì)模式中。其中比較明顯的就是singleton和proxy模式。
singleton
單例模式的實(shí)現(xiàn)一般都有兩種方式,要么在調(diào)用之前就創(chuàng)建好單例對(duì)象(eager way),要么在第一次調(diào)用的時(shí)候生成單例對(duì)象(lazy way),兩者對(duì)象的代碼大致是這樣的:
PS:在python中,這樣使用單例模式不是很pythonic,更好的辦法可見(jiàn)在stackoverflow上的這篇文章《creating-a-singleton-in-python》。另外在多線程環(huán)境下,要實(shí)現(xiàn)線程安全的單例還是很復(fù)雜的,具體討論可參見(jiàn)iteye上的分析。
proxy:
代理模式屬于責(zé)任型模式, 使得一個(gè)對(duì)象代表另一個(gè)對(duì)象進(jìn)行各種操作,常用場(chǎng)景包括remote proxy(遠(yuǎn)程代理),如RMI, RPC
virtual proxy(虛代理),根據(jù)需要?jiǎng)?chuàng)建開(kāi)銷很大的對(duì)象,如文檔中圖片的加載
(保護(hù)代理):控制對(duì)原始對(duì)象的訪問(wèn), 如智能指針
其中 viatual proxy是使用lazy loading很好的例子
Short-circuit evaluation:
短路求值在絕大多數(shù)編程語(yǔ)言都有實(shí)現(xiàn),比較常見(jiàn)的語(yǔ)法如下:
x and y(x && y)
x or y(x || y)
x if bool else y(bool? x : y )
短路求值基本上都是數(shù)學(xué)邏輯的體現(xiàn),如果第一個(gè)參數(shù)已經(jīng)能推導(dǎo)出這個(gè)表達(dá)式的意義,那么后面的參數(shù)是無(wú)需計(jì)算的。短路求值非常有用,不僅能避免無(wú)用的計(jì)算,對(duì)于邏輯判斷也非常有用。比如在python中,判斷一個(gè)對(duì)象的is_ok屬性為True,我們一般這么寫
if(obj.is_ok)
如果obj被賦值成了None,那么就會(huì)報(bào)一個(gè)異常,所以可以寫成
if(obj is not None and obj.is_ok)
python中,一些函數(shù)也有短路求值的特性,比如在這篇文章中提到的any函數(shù):
本意是希望對(duì)所有的element都計(jì)算,然后返回一個(gè)結(jié)果,但事實(shí)上由于短路求值, 可能后面很多的元素都不會(huì)再調(diào)用calc_and_ret
generator:
在python和javascript語(yǔ)言中都有g(shù)enerator,generator與普通的函數(shù)相比,可以多次(甚至無(wú)限次)返回,而且返回值是在需要的時(shí)候才生成。在python中,下面兩段代碼非常相似,但事實(shí)上差異非常大:
1 for x in [ii for i in xrange(10000)]2 # do sth with i3 4 for x in (ii for i in xrange(10000)]5 # do sth with i
generator更廣泛的應(yīng)用可以參見(jiàn)《python yield generator 詳解》。javascript中g(shù)enerator的語(yǔ)法和使用與python都非常類似,可以參見(jiàn)這篇文章。
函數(shù)式編程語(yǔ)言中的應(yīng)用:
lazy evaluation在函數(shù)式編程語(yǔ)言中使用得非常頻繁,python也可以當(dāng)做函數(shù)式編程語(yǔ)言來(lái)使用,而更為明顯的是haskell,在其首頁(yè)的features介紹里面就有大大的“l(fā)azy”
cache:
cache也是一種lazy思想,如果之前有計(jì)算結(jié)果,那么直接復(fù)用之前的結(jié)果就行了,干嘛還要重新計(jì)算呢?而且最開(kāi)始的緩存內(nèi)容, 也是在需要的時(shí)候才計(jì)算的,而不是一開(kāi)始就計(jì)算好。wiki上有python實(shí)現(xiàn)的簡(jiǎn)單例子:
Dirty Flag:
在《Dirty Flag模式及其應(yīng)用》一文中,列舉了Dirty Flag模式的諸多應(yīng)用場(chǎng)景。Dirty Flag顯然也是很明顯的lazy evaluation。比如《game programming pattern》中的例子:子模型的世界坐標(biāo)取決于父模型的世界坐標(biāo)以及子模型在父模型坐標(biāo)空間的相對(duì)坐標(biāo),如果父模型的世界坐標(biāo)變化時(shí)就主動(dòng)去重新計(jì)算子模型的坐標(biāo),因?yàn)閮蓭g父模型的坐標(biāo)可能多次變換,往往會(huì)造成冗余的計(jì)算。所以Dirty Flag只是在父模型坐標(biāo)變化的時(shí)候標(biāo)記,繪制的時(shí)候再計(jì)劃所有受影響的模型的世界坐標(biāo)。
CopyOnWrite:
CopyOnWrite即寫時(shí)復(fù)制,如果大家對(duì)一份資源只有讀請(qǐng)求時(shí),那么資源是可以共享的,當(dāng)某個(gè)訪問(wèn)者需要修改資源(寫操作)時(shí),就將資源拷貝一份給該訪問(wèn)者使用。即資源的拷貝被延遲到了第一次"寫"的時(shí)候。CopyOnWrite最廣為人知的兩個(gè)應(yīng)用場(chǎng)景,一個(gè)是Unix like系統(tǒng)fork調(diào)用產(chǎn)生的子進(jìn)程共享父進(jìn)程的地址空間,知道寫操作才會(huì)拷貝一份。另一個(gè)是java中的copyonwrite容器,用于多線程并發(fā)情況下的高效訪問(wèn),cookshell上有對(duì)copyonwrite容器的詳細(xì)介紹。
web開(kāi)發(fā)中的惰性加載與惰性預(yù)加載:
在web前端和APP開(kāi)發(fā)中,當(dāng)提到惰性加載或者動(dòng)態(tài)加載,大家往往會(huì)想到分頁(yè)、輪播圖、瀑布流,這些都體現(xiàn)了惰性加載的思想。其中,瀑布流在出諸多圖片分享網(wǎng)站中使用非常廣泛,比如花瓣網(wǎng),當(dāng)滑動(dòng)到屏幕底部的時(shí)候才會(huì)去加載新的內(nèi)容。為什么要使用惰性加載,第一個(gè)是用戶體驗(yàn)的問(wèn)題,圖片資源流量比較大,一次加載太多對(duì)服務(wù)器和瀏覽器壓力都很大,對(duì)帶寬要求也很高;另外,可能用戶根本就不會(huì)滑動(dòng)到最下面,多加載的內(nèi)容就白白浪費(fèi)了。
當(dāng)然太”Lazy”了也是不好的,總不能讓玩家滑動(dòng)到底部才一邊顯示loading icon,一邊開(kāi)始加載。為了提高用戶體驗(yàn),這類網(wǎng)站也會(huì)做預(yù)加載(predictive loading),即多準(zhǔn)備一兩頁(yè)的內(nèi)容,或者在滑屏到一定程度時(shí)開(kāi)始加載新的一頁(yè),不過(guò)這樣的預(yù)加載也是惰性預(yù)加載(lazy predictive loading)。
總結(jié):
回到頂部
本文列舉了惰性計(jì)算在編程中的一些具體例子,希望能給自己以及大家有所啟發(fā),在以后遇到問(wèn)題的時(shí)候多一種解決思路。由于本人編程領(lǐng)域以及編程語(yǔ)言的局限性,肯定還有諸多遺漏,歡迎大家在評(píng)論里補(bǔ)充。
references:
lazy loading
lazy initializing
lazy evaluation
Short-circuit_evaluation
CopyOnWrite
Dirty Flag模式及其應(yīng)用
python yield generator 詳解
Dirty Flag
Lazy initialization
本文版權(quán)歸作者xybaby(博文地址:http://www.cnblogs.com/xybaby/)所有,歡迎轉(zhuǎn)載和商用,請(qǐng)?jiān)谖恼马?yè)面明顯位置給出原文鏈接并保留此段聲明,否則保留追究法律責(zé)任的權(quán)利,其他事項(xiàng),可留言咨詢。