最近在做乙個web的資料統計的優化,但是由於資料量大,執行一次sql統計要比較長的時間(一般700ms算是正常)。
正常的做法只要加個快取就好了。
但是同時業務要求此資料最多1分鐘就要更新,而且這一分種內資料可能會有較多變化(而且原系統不太易擴充套件)。
也就是說快取1分鐘就要失效重新統計,而且使用者訪問這頁還很是頻繁,如果使用一般快取那麼使用者體驗很差而且很容易造成超時。
看到以上需求,第乙個進入我大腦的就是從前做遊戲時接觸到的ddraw的雙緩衝顯示方式。
在第一幀顯示的同時,正在計算第二幀,這樣讀取和計算就可以分開了,也就避免了讀取時計算,提高了使用者體驗。
我想當然我們也可以將這種方式用於快取的策略中,但這樣用空間換取時間的方式還是得權衡的,因為並不是所有時候都值得這麼做,但這裡我覺得這樣做應該是最好的方式了。
注:為了可以好好演示,本篇中的快取都以ienumerable的形式來儲存,當然這個文中原理也可以應用在webcache中。
這裡我使用以下資料結構做為儲存單元:
namespace chcache有了這個資料結構我們就可以將資料實現兩份儲存。再利用一些讀寫策略就可以實現上面我們講的快取方式。///
/// 次要儲存介質
///
public
object secondary
///
/// 是否正在使用主要儲存
///
public
bool isprimary
///
/// 是否正在更新
///
public
bool isupdating
///
/// 是否更新完成
///
public
bool isupdated }}
整個的快取我們使用如下快取類來控制:
/*這裡我只實現了插入乙個快取,以及讀取的方法。* * chsword
* date: 2009-3-31
* time: 17:00
* */
using system;
using system.collections;
using system.collections.generic;
using system.threading;
namespace chcache
public
void add(string key,func func)
else );
console.writeline("end first write");}}
///
/// 讀取時所用的索引
///
///
///
public
object
this[string key]
var ret = elem.isprimary ? elem.primary : elem.secondary;
var b = elem.isprimary ? "from 1" : "form 2";
return ret + b;}}
dictionary store
public ienumerator getenumerator() }}
我讀取快取單元的邏輯是這樣的
從2個不同快取讀取當然是很容易了,但是比較複雜的就是向快取寫入的過程:
這裡讀取資料以及寫入快取時我使用了乙個委託,在其它執行緒中僅在需要執行時才會執行。
這裡除了首次寫入快取占用主線程時間(讀取要等待)以外,其它時間都可以無延時的讀取,實現了無縫的快取。
但我們在委託中要操作快取的元素medium,所以要傳遞引數進其它執行緒,所以我這裡使用了乙個輔助類來傳遞引數進入其它執行緒:
using system;這樣我們就實現了在另個執行緒讀取資料的過程,這樣就在任何時候讀取資料時都會無延時直接讀取了。namespace chcache
medium medium
///
/// 通過建構函式來傳遞引數
///
/// 快取單元
/// 讀取資料的委託
public threadhelper(medium m,func fun)
///
/// 執行緒入口,threadstart委託所對應的方法
///
public
void doit()
else
medium.isupdated = true;
medium.isupdating = false;}}
}
最後我們寫乙個主函式來測試一下效果
/*得到如下資料:* * chsword
* date: 2009-3-31
* time: 16:53
*/using system;
using system.threading;
namespace chcache
}///
/// 獲取資料的方法,假設是從資料庫讀取的,費時約4秒
///
///
static
object getvalue()}}
這樣就實現了平滑的讀取快取資料而沒有任何等待時間
當然這裡還有些問題,比如說傳遞不同引數時的解決方法,但是由於我僅是在乙個統計時需要這種快取提高效能,所以暫沒有考慮通用的傳參方式。
cat chen一語提醒,其實做快取的提前載入沒有必要使用2個快取的,於是將列子改了改:無縫快取讀取簡化:僅lambda表示式傳遞委託
無縫的快取讀取 雙儲存快取策略
最近在做乙個web的資料統計的優化,但是由於資料量大,執行一次sql統計要比較長的時間 一般700ms算是正常 正常的做法只要加個快取就好了。但是同時業務要求此資料最多1分鐘就要更新,而且這一分種內資料可能會有較多變化 而且原系統不太易擴充套件 也就是說快取1分鐘就要失效重新統計,而且使用者訪問這頁...
無縫的快取讀取 雙儲存快取策略
最近在做乙個web的資料統計的優化,但是由於資料量大,執行一次sql統計要比較長的時間 一般700ms算是正常 正常的做法只要加個快取就好了。但是同時業務要求此資料最多1分鐘就要更新,而且這一分種內資料可能會有較多變化 而且原系統不太易擴充套件 也就是說快取1分鐘就要失效重新統計,而且使用者訪問這頁...
仿okhttp快取策略的資料快取
之前在面試中經常被問到看過哪些優秀的原始碼,吧啦吧啦說一大堆,問學到了哪些東西,吧啦吧啦又說一大堆,但是其實都是紙上談兵,並未結合到專案中。比如說okhttp的快取策略,okhttp的快取做的還是不錯的,有快取沒有過期就直接用,有快取過期了先用過期的,然後再聯網儲存,沒有快取再去聯網請求,之前也寫過...