無縫的快取讀取 雙儲存快取策略

2021-09-08 06:46:11 字數 3139 閱讀 1681

最近在做乙個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的快取做的還是不錯的,有快取沒有過期就直接用,有快取過期了先用過期的,然後再聯網儲存,沒有快取再去聯網請求,之前也寫過...