作者的設(shè)計思路和細節(jié)參看這里:YYCache 設(shè)計思路
YY給我印象最深的是他做事的方式,文章里寫到他調(diào)研了多個相關(guān)的庫,包括開源和閉源的。按照他一貫的風(fēng)格,有性能評測。不過這次咋沒有單元測試呢?:)
我簡單了畫了一張類圖,(原諒我笨拙的Keynote技能,我自己已經(jīng)不能容忍了,已將Keynote學(xué)習(xí)列入日程。)

緩存YYCache包括兩層
內(nèi)存緩存
磁盤緩存
他們可以單獨使用,也可以組合使用。
內(nèi)存緩存基于雙向鏈表和字典實現(xiàn)的。考慮到緩存的局部性,性能接近O(1).
磁盤緩存同時使用了文件和數(shù)據(jù)庫的方式,根據(jù)測試的結(jié)果,sqlite的寫入性能高于文件寫入,但是讀取性能,在讀大文件是(根據(jù)內(nèi)存頁設(shè)置不同,值會不一樣,這個值在20K左右),性能低于文件讀。所以數(shù)據(jù)中只存了文件的名稱。將文件的實際內(nèi)容寫在磁盤上。
這里有個典型的應(yīng)用是網(wǎng)絡(luò)圖片庫的下載,用到內(nèi)存+磁盤的兩級緩存,因為圖片一般不會小,也將圖片保存在磁盤上。在作者的YYWebImage庫里也用到了這個緩存庫。
留有的疑問
Open-sourcing PINCache(多線程同步問題)
https://engineering.pinterest.com/blog/open-sourcing-pincache
問題:("TMMemoryCache 在設(shè)計時,主要目標是線程安全,它把所有讀寫操作都放到了同一個 concurrent queue 中,然后用 dispatch_barrier_async 來保證任務(wù)能順序執(zhí)行。"
barrier準確的說應(yīng)該是保證被包裹的代碼塊在并發(fā)隊列中執(zhí)行時的獨占性,就如同跑在串行隊列中一樣,不知道這樣說對不對。
還有想請教一點:它錯誤的用了大量異步 block 回調(diào)來實現(xiàn)存取功能,以至于產(chǎn)生了很大的性能和死鎖問題,這個能否多解釋一下?)
提問者的回答
“看了PinCache 的源碼明白了,PinMemoryCache 同步讀的時候,是真正的同步讀,并且用信號量控制了同步讀在并發(fā)隊列的并行量;而 TMMemCache的同步讀,其實是用信號量將異步變成了同步,但是會存在并發(fā)隊列忙碌時,無法執(zhí)行回調(diào)發(fā)信號造成死鎖?!?/p>
思維很嚴密,該做判斷的地方都判斷到了。代碼只有想清楚才能寫清楚!要不然,寫多少測試用例都沒用,不知道做到了多少才是合適的,不多也不少。
- (BOOL)saveItemWithKey:(NSString*)key value:(NSData*)value filename:(NSString*)filename extendedData:(NSData*)extendedData {
if(key.length== 0 || value.length== 0)returnNO;
if(_type==YYKVStorageTypeFile&& filename.length== 0) {
returnNO;
}
if(filename.length) {
if(![self_fileWriteWithName:filenamedata:value]) {
returnNO;
}
if(![self_dbSaveWithKey:keyvalue:valuefileName:filenameextendedData:extendedData]) {
[self_fileDeleteWithName:filename];
returnNO;
}
returnYES;
}else{
if(_type!=YYKVStorageTypeSQLite) {
NSString*filename = [self_dbGetFilenameWithKey:key];
if(filename) {
[self_fileDeleteWithName:filename];
}
}
return[self_dbSaveWithKey:keyvalue:valuefileName:nilextendedData:extendedData];
}
}