日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

YYCache深入学习

發布時間:2025/3/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 YYCache深入学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

深知,源碼還是一點點讀,加點讀書筆記,才可以深入挖掘,因此還是覺得每次讀源碼都記錄一番,無論好壞,如有寫錯,請斧正

簡介

YYCahce 是作為 ibireme 大神開源的一個YYkit組件庫中的一部分,YYCache提供了內存緩存,和持久性的硬盤緩存。

一個合理緩存應該有的設計

  • 合理的增刪改查接口
  • 高速緩存,提高常用緩存的返回性能和效率
  • 低速緩存,磁盤大文件緩存
  • 良好緩存限制策略
  • 高性能,線程安全

基本設計思路

YYCache 提供對外的整合接口,YYMemoryCache 提供內存存儲緩存,通過lru算法進行處理,YYDiskCache提供file和sqlite3的兩種持久化存儲方式

YYMemoryCache

YYMemoryCahce 作為一個內存緩存,提供高速緩存,并且因為內存有限,需要進行一定的限制

  • 線程安全

    在頻率高的并發數據操作中,必須保證線程安全,不然拿到的數據不符合預期,或者導致讀寫沖突 在YYMemoryCache中,采用的pthread_mutex加鎖

    pthread_mutex 定義了一組跨平臺的線程相關的 API,pthread_mutex 表示互斥鎖。互斥鎖的實現原理與信號量非常相似,不是使用忙等,而是阻塞線程并睡眠,需要進行上下文切換。

    // 主要使用api pthread_mutex_lock(&mutex); // 申請鎖 // 臨界區pthread_mutex_unlock(&mutex); // 釋放鎖 復制代碼

    pthread_mutex支持遞歸鎖,遞歸鎖,就是在內部加鎖調用的時候,遞歸了自身,這樣子,會導致死鎖。

    • pthread_mutex則支持遞歸處理 attr PTHREAD_MUTEX_RECURSIVE

    • memory中使用pthread,在循環釋放的時候,通過pthread_mutex_trylock實現簡單的自旋鎖

    原文:OSSpinLock 和 dispatch_semaphore 都不會產生特別明顯的死鎖,所以我也無法確定用 dispatch_semaphore 代替 OSSpinLock 是否正確。能夠肯定的是,用 pthread_mutex 是安全的。

  • LRU

  • 最近使用優先,也就是認為,最近使用的,最大可能性會再次用到 里面實現用到一個雙向鏈表的結構進行處理,使用到的就會被移動到表頭 在刪除釋放的時候,就會從隊尾進行刪除釋放

  • 鍵值對存儲操作
  • 通過創建鏈表節點node,進行間接操作數據

    #pragma mark - _YYLinkedMapNode @interface _YYLinkedMapNode : NSObject {// 類似C中的private_extern,使用@private的話,限制太大,@package在類的鏡像外進行引用就會報錯// 使用@public @protect等的話,就沒什么限制的// 目的是,限制在本文件中使用@package__unsafe_unretained _YYLinkedMapNode *_prev; // 通過dic進行持有__unsafe_unretained _YYLinkedMapNode *_next; // 通過dic進行持有id _key;id _value;NSUInteger _cost;NSTimeInterval _time; } @end 復制代碼
  • 限制策略
  • // 限制條件有3個,age cost count ,一般情況下默認都不做限制 /// 個數限制 @property NSUInteger countLimit; /// 過期時間 @property NSTimeInterval ageLimit; /// 存儲消耗限制,setObject的時候時候把內存大小的存進去 @property NSUInteger costLimit;@property BOOL shouldRemoveAllObjectsWhenEnteringBackground; // 進入后臺檢查限制刪除緩存,默認YES @property BOOL shouldRemoveAllObjectsOnMemoryWarning; // 收到內存警告的時候復制代碼

    MemoryCache中使用的LRU的的算法進行刪除緩存,當超過一定的限制的時候,會進行循環清理,也就是說,memory里面的東西并不是存進去就會在app的生命周期中一直存在的,可能會被釋放掉。因此外部在使用的時候,需要判空處理的,如果為nil,則認為緩存已經失效,需要重新更新。

    因此,YYMemoryCahce并不是數據在app的生命周期會被一直保留的,所以,在使用YYCahce最外層接口的時候,YYCache是會通過YYMemoryCache提供高速緩存,同時存入到低速緩存中。

    獲取的時候,YYMemoryCache獲取不到,則會詢問YYDiskCache。

  • 某些小技巧,用于提供性能
  • 會在一段時間,自行檢查是否超過限制策略,超過則循環釋放。 YYMemoryCache默認在進入后臺的時候會進行檢查。 因為一次釋放太多,會導致資源消耗過大,因此,通過dispatch_aync block的方式,放到后臺線程釋放


    YYDiskCache

  • 線程安全
  • disk中使用dispatch_semaphore信號量進行處理

    dispatch_semaphore 是信號量,但當信號總量設為 1 時也可以當作鎖來。在沒有等待情況出現時,它的性能比 pthread_mutex 還要高,但一旦有等待情況出現時,性能就會下降許多。相對于 OSSpinLock 來說,它的優勢在于等待時不會消耗 CPU 資源。對磁盤緩存來說,它比較合適。

    dispatch_semaphore是屬于閑等待,CPU不會消耗,因此,在做磁盤緩存的時候,用時較長,需要等待的話,會比較節省資源

    • OSSpinLock 自旋鎖,不安全,所以使用了dispatch_semaphore進行處理,因為大文件,需要等待的情況較多
  • 大文件處理
    • YYKVStorage 通過key value的一個封裝,實現增刪改查

    • YYKVStorage 實現細節:

      • 提供對應的sqlite3的db增刪改查的接口,在操作的過程都做了防御式的操作
      - (BOOL)_dbClose {// 關閉數據庫if (!_db) {return YES;}int result = 0;BOOL retry = NO;BOOL stmtFinalized = NO;if (_dbStmtCache) {_dbStmtCache = NULL;}do {retry = NO;result = sqlite3_close(_db);if (result == SQLITE_BUSY || result == SQLITE_LOCKED) {// 如果sqlite被占用,那進行stmt的析構操作,讓其釋放資源// 在重新試一次if (!stmtFinalized) {stmtFinalized = YES; //析構sqlite3_stmt *stmt;// sqlite3_stmt 是一種輔助數據結構,用于操作二進制數據// 循環釋放所有的sqlite stmtwhile ((stmt = sqlite3_next_stmt(_db, nil))) {sqlite3_finalize(stmt); //析構 所有的sqlite stmt的輔助retry = YES; // 然后重試,}}} else if (result != SQLITE_OK) {// 關閉失敗// 輸出 錯誤日志NSLog(@"關閉失敗");}} while (retry);_db = NULL;return YES;}- (BOOL)_dbCheck {if (_db) {// 如果重試錯誤的次數小于限定次數,并且大于最小重試時間,則重新進行打開和初始化檢查if (_dbOpenErrorCount < kMaxErrorRetryCount &&CACurrentMediaTime() - _dbLastOpenErrorTime > kMinRetryTimeInterval) {return [self _dbOpen] && [self _dbInitialize];} else {return NO;}}return YES; // 正常 } 復制代碼
      • 對sqlite的stmt也做了緩存,加速其性能
      // 獲取緩存中的stmt,用sql做key - (sqlite3_stmt *)_dbPrepareStmt:(NSString *)sql {if (![self _dbCheck] || sql.length == 0 || !_dbStmtCache) return NULL;sqlite3_stmt *stmt = (sqlite3_stmt *)CFDictionaryGetValue(_dbStmtCache, (__bridge const void *)(sql));if (!stmt) {// 如果stmt為空的話int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);if (result != SQLITE_OK) {// 如果不成功NSLog(@"創建stmt失敗");return NULL; // 返回空}CFDictionarySetValue(_dbStmtCache, sql.UTF8String, stmt); // 緩存起來,都是同一個stmt,每次創建的話,會大量消耗資源,因此這里做了緩存} else {sqlite3_reset(stmt);}return stmt; } 復制代碼
    • 存儲方式有三個模式

      • 文件
      • sqlite3
      • 混合 // 混合的情況有個閾值,大于閾值,則存文件
    • db sqlite3的使用細節

      • sqlite3_stmt 操作數據的輔助數據接口,用于執行sql,并且返回結果
      • stmt 也進行做了緩存,因為這個sql會重復不定期使用
    • 優化: 可以升級最新版本的sqlite3,以此提高效率


    YYCache

    提供了增刪改查的API,底下調用的YYMemoryCache和YYDiskCache,封裝了一些基本邏輯。在save的時候,會保存到YYMemoryCache和YYDiskCache,讀取的時候,會優先讀取YYMemoryCache實現高速緩存,再讀取低速緩存。

    參考

    實際上在看的時候,下面這位大佬寫得更加清晰的,之所以我按自己的理解再寫一次,也是為了讓自己更好的研究,根據所有學習技巧來說,最重要的還是應用,因此有了這篇文章,希望之后能逐漸寫出一些更好blog

    從 YYCache 源碼 Get 到如何設計一個優秀的緩存 - https://juejin.im/post/59f6e3b051882534af253d4a

    ibireme blog - http://blog.ibireme.com/category/tec/ios-tec/

    總結

    以上是生活随笔為你收集整理的YYCache深入学习的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。