選擇你所需要的緩存

我們?cè)谔幚頂?shù)據(jù)的時(shí)候惑艇,第一步就會(huì)接觸到緩存。這里就來(lái)看看應(yīng)該選擇什么樣的緩存來(lái)解決你的問(wèn)題胸梆。

在一般的場(chǎng)景下敦捧,我們并不會(huì)去考慮緩存的所帶來(lái)的優(yōu)化與損耗,因?yàn)榇蟛糠謭?chǎng)景這一點(diǎn)損耗都可以忽略不計(jì)碰镜,但是在某些極限情況下,這就不能被忽略了习瑰。那么我們就需要來(lái)思考采用什么樣的方式去緩存數(shù)據(jù)绪颖。

首先,緩存可以被分為兩類:

  • 內(nèi)存緩存
  • 磁盤緩存甜奄,也可以稱為持久化

那么我們按照這兩者來(lái)分析下柠横,現(xiàn)在比較流行的幾種方式。

Memory Cache

NSCache

官方提供的緩存一般來(lái)說(shuō)已經(jīng)足夠使用了课兄,線程安全牍氛,功能也特別完善,擁有靈活的控制烟阐,在內(nèi)存不足時(shí)也會(huì)回收內(nèi)存搬俊。底層應(yīng)該是基于hash表的,所以性能表現(xiàn)也十分優(yōu)秀蜒茄。

但是系統(tǒng)實(shí)現(xiàn)的緩存失效策略卻是未知的唉擂,無(wú)法保證是LRU策略。同時(shí)NSCache會(huì)在系統(tǒng)回到后臺(tái)的時(shí)候清空緩存檀葛,如果你希望在app的生命周期內(nèi)都可以緩存玩祟,那么NSCache難以做到。

一般來(lái)說(shuō)NSCache是首選屿聋,除非需要一些特殊的要求空扎。

NSArray & NSDictionary

這兩者是系統(tǒng)內(nèi)置集合類型,可以用作緩存數(shù)據(jù)润讥,但是是非線程安全的转锈,在使用中需要特別小心,同時(shí)需要自己去控制緩存失效象对。

在數(shù)據(jù)量比較小的時(shí)候黑忱,這兩者都是沒(méi)有問(wèn)題的,但是在數(shù)據(jù)量變得龐大的時(shí)候就會(huì)有一定的性能問(wèn)題。

由于NSArray是數(shù)組實(shí)現(xiàn)甫煞,位置查找的效率為1菇曲,內(nèi)容查找的效率為n,所以在大量頻繁的內(nèi)容查找中抚吠,會(huì)降低其性能常潮。這時(shí)候推薦NSSet或者NSOrderedSet來(lái)替代NSArray。NSSet的底層是hash表楷力。

在使用hash表的時(shí)候喊式,如何來(lái)更好的實(shí)現(xiàn)其查找性能呢,就需要保持key的hash隨機(jī)分布萧朝。一般來(lái)說(shuō)我們都會(huì)使用string作為key岔留,在自己實(shí)現(xiàn)的key值別忘了重寫hash。

在某些情境下检柬,使用集合類型也非常有效献联。

其他

也可以根據(jù)自己的需求來(lái)設(shè)計(jì)自己的容器類,比如自平衡二叉樹(shù)何址、B樹(shù)等里逆。不過(guò)首先要了解上述幾種是否已經(jīng)滿足自己的需求。

Persistent

持久化緩存擁有多種不同的數(shù)據(jù)格式和存儲(chǔ)方式用爪,這里按照幾種方式和開(kāi)源庫(kù)來(lái)看看各自的方案原押。

NSUserDefaults

這是系統(tǒng)提供的最簡(jiǎn)單的一種保存數(shù)據(jù)的方式,自帶了緩存和同步機(jī)制偎血,利用的是NSCoding的方式诸衔,所以NSCoding擁有的缺陷UserDefault也會(huì)擁有。

當(dāng)數(shù)據(jù)量增多變大烁巫,會(huì)導(dǎo)致plist文件太大署隘,從而影響加載性能,所以只能保存少量的小型數(shù)據(jù)亚隙。

NSCoding

這是系統(tǒng)提供的持久化方案磁餐,不僅僅保存了數(shù)據(jù),同時(shí)也保存了類別信息阿弃。但這也帶來(lái)了部分缺陷诊霹,那就是數(shù)據(jù)兼容問(wèn)題。

當(dāng)軟件升級(jí)時(shí)渣淳,修改了類名脾还,或者改動(dòng)了內(nèi)部成員實(shí)現(xiàn),就可能導(dǎo)致數(shù)據(jù)錯(cuò)誤設(shè)置崩潰入愧。所以需要小心控制數(shù)據(jù)版本信息鄙漏。

由于這種方式是一次性的讀取與寫入嗤谚,在數(shù)據(jù)量大的時(shí)候也會(huì)產(chǎn)生一些問(wèn)題。同時(shí)這種方式并不適合部分讀取部分修改的場(chǎng)景怔蚌,如果數(shù)據(jù)比較大需要重新考慮巩步。

JSON

另一種代替NSCoding的方式便是使用JSON來(lái)保存,雖然在數(shù)據(jù)兼容性上會(huì)比NSCoding稍微優(yōu)秀一些桦踊,但依然沒(méi)有根本解決這個(gè)問(wèn)題椅野,所以這是一個(gè)可選方案。

YYKit

YYKit使用了LRU策略籍胯,明確了緩存失效策略竟闪。

內(nèi)存緩存使用了線性鏈表+NSDictionary來(lái)實(shí)現(xiàn),由于LRU的特性杖狼,插入永遠(yuǎn)在開(kāi)始炼蛤,而刪除永遠(yuǎn)在結(jié)尾,所以擁有較高的性能蝶涩。但是查找還是依賴于hash表來(lái)實(shí)現(xiàn)鲸湃。這樣在插入和查找都避免了對(duì)方的缺陷,實(shí)現(xiàn)了更加高效的結(jié)果子寓。缺點(diǎn)是需要同時(shí)保存和修改兩份數(shù)據(jù)索引。

磁盤緩存使用了sqlite來(lái)保存文件緩存信息(filename, last_modify_time)笋除,所以在讀寫小數(shù)據(jù)的時(shí)候(20KB)會(huì)直接在sqlite中讀寫斜友,而不會(huì)生成一個(gè)獨(dú)立的文件。所以在小文件和未命中的情況下效率會(huì)高很多垃它。而讀寫大文件時(shí)鲜屏,效率會(huì)降低一些,考慮到sqlite的緩存和執(zhí)行国拇,并不會(huì)降低太多洛史。由于sqlite對(duì)時(shí)間創(chuàng)建了索引,所以在緩存過(guò)期查找上面會(huì)優(yōu)秀一些酱吝。這種設(shè)計(jì)解決了小文件和未命中的效率問(wèn)題也殖,但是并不能實(shí)現(xiàn)高并發(fā)讀寫文件。

這種按照數(shù)據(jù)量來(lái)區(qū)分?jǐn)?shù)據(jù)存儲(chǔ)方式的方法解決了大文件和小文件之間的性能差別务热,但也給緩存系統(tǒng)帶來(lái)了一定的復(fù)雜性忆嗜。同時(shí)如果sqlite的索引失效會(huì)導(dǎo)致查找效率的降低。

YYCache帶來(lái)了一種通用型的存儲(chǔ)方式崎岂,但在很多時(shí)候還是需要自己來(lái)實(shí)現(xiàn)特定的需求捆毫。

PINCache

使用了大量的Lock來(lái)處理多線程讀寫,擁有異步讀寫接口冲甘,沒(méi)有太多的特別優(yōu)化绩卤。

磁盤緩存單純使用了文件緩存途样,在初始化的時(shí)候就把整個(gè)目錄及其元素的屬性讀到內(nèi)存,來(lái)提高效率濒憋,但是使用的是數(shù)組存儲(chǔ)何暇,效率一般。

SPTPersistentCache

他將數(shù)據(jù)信息通過(guò)memory map的方式寫到了文件頭部跋炕,說(shuō)是為了并發(fā)讀寫赖晶,但這也時(shí)每次更新updateTime需要寫整個(gè)文件,這樣必定會(huì)導(dǎo)致性能降低辐烂。個(gè)人建議還是把文件信息寫到另一個(gè)文件中遏插,方便內(nèi)存緩存。

這種方式比較適合的場(chǎng)景是只讀數(shù)據(jù)纠修,對(duì)于經(jīng)常變化的數(shù)據(jù)反而可能會(huì)降低性能胳嘲。

Haneke & SDWebImage

這兩者非常相似,Haneke功能更少扣草,但是更加緊湊了牛,代碼結(jié)構(gòu)也更加好。而SDWebImage功能非常完善辰妙,使用的人也非常的多鹰祸。但也并非沒(méi)有瑕疵。

圖片緩存讀取全部在一個(gè)子線程中進(jìn)行密浑,導(dǎo)致在高并發(fā)讀取的時(shí)候會(huì)阻塞線程蛙婴,同樣下載和解碼也會(huì)有類似的問(wèn)題。這么設(shè)計(jì)同時(shí)也是為了保證線程安全尔破,所以采用了順序隊(duì)列的操作街图,但是對(duì)于單文件來(lái)說(shuō),這樣是正確的懒构,對(duì)于多文件來(lái)說(shuō)沒(méi)有必要這樣做餐济。在目前移動(dòng)端以及pc端來(lái)看,性能的瓶頸還不在這個(gè)地方胆剧,依然在IO上面絮姆,所以除非特殊情況,不會(huì)出現(xiàn)性能問(wèn)題赞赖。

圖片的二次處理能力不夠(比如手動(dòng)加圓角滚朵,裁剪,濾鏡)前域,需要自己去處理并且緩存辕近,這對(duì)于一個(gè)圖片庫(kù)來(lái)說(shuō)是一個(gè)遺憾,好在目前大部分工作CDN都會(huì)幫我們做掉匿垄。

預(yù)加載圖片無(wú)法和正常加載使用同一套機(jī)制移宅,預(yù)加載和正常加載如果同時(shí)觸發(fā)會(huì)加載2次归粉。SD沒(méi)有考慮到預(yù)加載和正常加載使用同一個(gè)Operation緩存,導(dǎo)致雙方都會(huì)觸發(fā)真實(shí)的下載漏峰,從而浪費(fèi)了流量糠悼。

作為一個(gè)圖片庫(kù),圖片一般內(nèi)容都比較大浅乔,所以采用了文件緩存的機(jī)制倔喂,使用key作為文件名。由于文件系統(tǒng)自身?yè)碛械木彺婢肝栽诓檎业男噬喜⒉坏汀?/p>

FastImageCache

這也是一個(gè)圖片緩存方案席噩,增加了處理圖片的一些中間件。

該作者認(rèn)為效率問(wèn)題主要出現(xiàn)在圖片從磁盤讀取到內(nèi)存贤壁,再進(jìn)行解壓悼枢,以及渲染前的內(nèi)存拷貝。解決這類問(wèn)題的最好方法就是進(jìn)行memory map脾拆,將處理好的內(nèi)容直接寫入文件馒索,這樣在下一次載入的時(shí)候就不需要重新處理了。

作者也指出了這種方式會(huì)導(dǎo)致一張高壓縮率的圖片名船,進(jìn)行內(nèi)存映射后會(huì)變得很大绰上,這一非常大的缺陷。

內(nèi)存映射也是一種很好的方案渠驼,在存儲(chǔ)資源豐富渔期,而處理需要很長(zhǎng)時(shí)間的情況下,是最簡(jiǎn)單的處理方式渴邦。隨著現(xiàn)在設(shè)備性能的提高,一般不會(huì)存在處理的性能瓶頸拘哨,所以也需要按情景來(lái)判斷谋梭。

最后

這里分析了幾種內(nèi)存緩存和磁盤緩存的情況牡直,一般內(nèi)存緩存較為簡(jiǎn)單叙身,不會(huì)有太多的性能問(wèn)題,而磁盤緩存擁有很多的方案叙量,每種方案都有各自的適用場(chǎng)景产镐,需要根據(jù)自身的實(shí)際情況來(lái)選擇隘庄。

這里所列的幾種磁盤緩存都比較簡(jiǎn)單,之后會(huì)介紹一些比較復(fù)雜的存儲(chǔ)方案癣亚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末丑掺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子述雾,更是在濱河造成了極大的恐慌街州,老刑警劉巖兼丰,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異唆缴,居然都是意外死亡鳍征,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門面徽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)艳丛,“玉大人,你說(shuō)我怎么就攤上這事趟紊〉” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵织阳,是天一觀的道長(zhǎng)眶蕉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)唧躲,這世上最難降的妖魔是什么造挽? 我笑而不...
    開(kāi)封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮弄痹,結(jié)果婚禮上饭入,老公的妹妹穿的比我還像新娘。我一直安慰自己肛真,他們只是感情好谐丢,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蚓让,像睡著了一般乾忱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上历极,一...
    開(kāi)封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天窄瘟,我揣著相機(jī)與錄音,去河邊找鬼趟卸。 笑死蹄葱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锄列。 我是一名探鬼主播图云,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼邻邮!你這毒婦竟也來(lái)了竣况?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤筒严,失蹤者是張志新(化名)和其女友劉穎帕翻,沒(méi)想到半個(gè)月后鸠补,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嘀掸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年紫岩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睬塌。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡泉蝌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出揩晴,到底是詐尸還是另有隱情勋陪,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布硫兰,位于F島的核電站诅愚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏劫映。R本人自食惡果不足惜违孝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泳赋。 院中可真熱鬧雌桑,春花似錦、人聲如沸祖今。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)千诬。三九已至耍目,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間徐绑,已是汗流浹背制妄。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泵三,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓衔掸,卻偏偏與公主長(zhǎng)得像烫幕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子敞映,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容