需要強調一點的是,我們這裡討論的僅僅是符合我提出的特定場景的快取容器,而不是乙個「執行緒安全的字典」。或者說,其實我這裡更強調的是「併發環境下」的「讀」效能,而不涉及idictionary的其他操作(如count),更不會關心如copyto、remove這類功能的效能。
public inte***ce我為這個介面提供了幾種最基本實現,無論是「讀」還是「寫」,都是最直接的,並不對任何特殊的情況(如key缺失,key重複)進行處理。例如immutablemapcache:iconcurrentcache
public classimmutablemapcache是基於f#中的map而實現的讀寫操作。由於是immutable的集合,因此對它的讀操作不需要任何併發方面的保護——而寫操作理論上也是執行緒安全的,但是我這裡還是使用了lock。這是因為如果沒有lock的話,在實際併發的場景中容易出現「搖擺」的情況出現。試想,同時有2個執行緒正在新增元素,它們同時讀取了集合的當前狀態,但是在寫回的時候隻後乙個執行緒的操作生效,先寫回的執行緒的修改丟失了。當併發程度高的情況下,「搖擺」會更加嚴重。因此,無論是immutablemapcache,還是基於immutable dictionary的實現,在set操作中都使用lock進行保護。immutablemapcache
: iconcurrentcache
public void set(tkey key, tvalue value)}}
測試**如下:
static void cachebenchmark()請注意,這裡的測試都是在單執行緒環境下的。嚴格來說,這並不表示每種容器在多執行緒環境下的表現。事實上,即便是多執行緒環境下,不同實現隨併發程度的高低也會有所變化。因此,除了進行實驗和觀察結果之外,也必須結合實際情況進行思考,而不能簡單的「採納」這次實驗的結果。在這裡我們總共測試5種不同的實現:where tcache : iconcurrentcache
, new()
});codetimer.time(cachename + " (get from " + n + " elements)", 1, () =>
});}
}
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引數?也有小夥伴說問我。那今天,我們就來根據這個問題來聊聊在高併...