2012-01-22 89 views
0

我試圖優化字典比較操作對用作數據庫查詢緩存的字典的每個字符串鍵的性能。當前的代碼如下所示:字符串比較的並行優化

public void Clear(string tableName) 
{ 
    foreach (string key in cache.Keys.Where(key => key.IndexOf(tableName, StringComparison.Ordinal) >= 0).ToList()) 
    { 
     cache.Remove(key); 
    } 
} 

我是新來使用C#並行的特點,我想知道什麼是最好的辦法是將其轉換成並行操作,使多個字符串比較可能發生「同時」。高速緩存通常會變得非常大,因此使用Clear()進行維護的成本可能會相當高。

+3

「高速緩存通常會變得相當大」 - 您是否測量過性能瓶頸?如果不是,引入線程不會帶來任何影響並增加複雜性 –

+1

如果我是你,首先考慮優化我的緩存方法,而不是尋求並行化服務代碼。 – Lazarus

+0

我運行過性能分析器,告訴我在這個方法中有70%的樣本,特別是在IndexOf()中。不幸的是我受限於現有框架使用這種緩存方法。我想強制緩存中元素的數量上限,但這不是一個選項。 – dahvyd

回答

1

使您的cache對象爲ConcurrentDictionary並使用TryRemove而不是Remove

這將使您的緩存線程安全;然後,可以調用當前的foreach循環是這樣的:

Parallel.ForEach(cache.Keys, key => 
{ 
    if(key.IndexOf(tableName, StringComparison.Ordinal) >= 0) 
    { 
     dynamic value; // just because I don't know your dictionary. 
     cache.TryRemove(key, out value); 
    } 
}); 

希望給你一個起點。

+2

這可能比沒有線程的串行刪除更慢。 – SLaks

+0

你可以精心設計嗎? – bevacqua

+0

線程安全很貴 – SLaks

1

您的方法無法在Dictionary<string, Whatever>上正常工作,因爲該類對於多個作者不是線程安全的,因此同時刪除可能會導致各種問題。

因此,您將不得不使用鎖來同步刪除,因此會使字典的訪問基本上是單線程的。關於可以在線程中同時安全完成的唯一事情是Where中的比較。

您可以使用ConcurrentDictionary,因爲它使用條紋鎖可以減少這種影響。儘管如此,它仍然不是最好的方法。

如果您從字符串構建密鑰以便測試密鑰是否以子密鑰開頭,並且經常需要刪除整個子密鑰,那麼您可以嘗試使用Dictionary<string, Dictionary<string, Whatever>>。添加或更新會變得更加昂貴,但清除將成爲O(1)從較高級字典中刪除一個值的方式。

+0

謝謝你的想法,但我不能承擔任何額外的開銷。 – dahvyd

+0

什麼樣的額外開銷?你試圖平行清理的想法固有的開銷。拆分查詢的開銷會影響到這不會造成什麼影響? –

0

我以前曾經使用字典作爲緩存,而我之前做的事情是「清除」緩存,即每個條目我還包括它的包含時間,然後隨時請求一個條目我刪除舊條目。對我來說,性能影響最小,但如果需要,您可以實現一個隊列(Tuple<DateTime, TKey>,其中TKey是字典中鍵的類型)作爲索引來保存這些時間戳,因此您無需每次遍歷整個字典。無論如何,如果您不得不考慮這些問題,現在可以考慮使用專門的緩存服務器了。對我來說,共享緩存(http://sharedcache.codeplex.com)已經足夠好了。