併發環境下的快取容器效能優化(下) 效能測試

2021-09-05 22:04:04 字數 2288 閱讀 1942

需要強調一點的是,我們這裡討論的僅僅是符合我提出的特定場景的快取容器,而不是乙個「執行緒安全的字典」。或者說,其實我這裡更強調的是「併發環境下」的「讀」效能,而不涉及idictionary的其他操作(如count),更不會關心如copyto、remove這類功能的效能。

public inte***ce 

iconcurrentcache

我為這個介面提供了幾種最基本實現,無論是「讀」還是「寫」,都是最直接的,並不對任何特殊的情況(如key缺失,key重複)進行處理。例如immutablemapcache:

public class 

immutablemapcache

: iconcurrentcache

public void set(tkey key, tvalue value)}}

immutablemapcache是基於f#中的map而實現的讀寫操作。由於是immutable的集合,因此對它的讀操作不需要任何併發方面的保護——而寫操作理論上也是執行緒安全的,但是我這裡還是使用了lock。這是因為如果沒有lock的話,在實際併發的場景中容易出現「搖擺」的情況出現。試想,同時有2個執行緒正在新增元素,它們同時讀取了集合的當前狀態,但是在寫回的時候隻後乙個執行緒的操作生效,先寫回的執行緒的修改丟失了。當併發程度高的情況下,「搖擺」會更加嚴重。因此,無論是immutablemapcache,還是基於immutable dictionary的實現,在set操作中都使用lock進行保護。

測試**如下:

static void cachebenchmark()

where tcache : iconcurrentcache

, new()

});codetimer.time(cachename + " (get from " + n + " elements)", 1, () =>

});}

}

請注意,這裡的測試都是在單執行緒環境下的。嚴格來說,這並不表示每種容器在多執行緒環境下的表現。事實上,即便是多執行緒環境下,不同實現隨併發程度的高低也會有所變化。因此,除了進行實驗和觀察結果之外,也必須結合實際情況進行思考,而不能簡單的「採納」這次實驗的結果。在這裡我們總共測試5種不同的實現:

cachebenchmark

>();

cachebenchmark

>();

cachebenchmark

>();

cachebenchmark

>();

cachebenchmark

>();

它們分別是:

rwlockslimdictionary:基於dictionary,使用readerwriterlockslim進行保護的快取容器。

rwlockdictionary:基於dictionary,使用readerwriterlock進行保護的快取容器。

immutable map:基於f#中map實現的快取容器。

immutable dictionary:基於不可變的雜湊表實現的快取容器。

concurrent dictionary:基於.net 4.0中提供的concurrent dictionary實現的快取容器。

執行環境是.net 4.0 beta 2,實驗進行三次。我們首先關注「寫」操作的結果,如下:

取平均值作為最後結果,並繪製成圖表:

那麼immutable dictionary又是什麼樣的呢?我們為其單獨進行一番實驗,減小實驗粒度,希望可以得到更清晰的結果:

for (int n = 100; n <= 10000; n += 100)

elements", n), 1, () =>

});}

將其結果繪製成圖表:

在寫方面,immutable dictionary的表現可謂殘不忍睹,但如果是「讀」的話,一切就都不一樣了:

將結果繪製成圖表:

從結果上我們可以得出一些有趣的結論。首先,readerwriterlockslim似乎會進行「自我調節」,一開始它的write lock開銷較大,但是隨著實驗的進行,它的開銷變小了很多。其次,基於immutable dictionary的實現自然因為其「read free」而表現最好,但是.net中concurrent dictionary的表現也相當出色,可謂遙遙領先於基於readerwriterlockslim的實現。而在「寫」操作測試時,它的表現也可圈可點,僅次於rwlockslimdictionary。我並不清楚concurrent dictionary的實現方式,有人說是lock free,也有人說是小粒度的鎖。這點可以通過閱讀**來得知,在這裡就不多作展開了。

高併發環境下的效能優化 非同步呼叫 Future

在業務處理過程中,我們會經常遇到一次使用者請求往往會涉及到多個操作。以獲取使用者資訊及其賬戶餘額為例,它包含了從使用者中心獲取使用者基本資訊 t1 以及從使用者金融中心獲取其對應的賬戶餘額資訊 t2 如果採用同步呼叫的話,總的響應時間將是 t1 t2。類似這種兩個子操作在執行過程中沒有依賴關係的呼叫...

docker下redis容器清理快取

1 登入至指定埠的redis服務 redis cli h 127.0.0.1 p 6379 其中,127.0.0.1可以寫成伺服器的ip位址,6379為埠號。注意 如果redis設定的有密碼要用 redis cli h 127.0.0.1 p 6379 a redis 不然執行下一步 keys 會報...

高併發場景下優化伺服器的效能實戰

tcp nodelay引數並不是在作業系統級別進行配置的,而是在tcp套接字上新增tcp nodelay引數來關閉粘包演算法,以便使資料報能夠立即投遞出去。寫在前面 最近,有小夥伴在群裡提問 linux系統怎麼設定tcp nodelay引數?也有小夥伴說問我。那今天,我們就來根據這個問題來聊聊在高併...