2015-06-04 35 views
6

讓我們假設我有以下一段代碼:LINQ環路條件

IEnumerable<string> allKeys = _cache.Select(o => o.Key); 
Parallel.ForEach(allKeys, key => _cache.Remove(key)); 

正如你所看到的,我檢索所有的鑰匙,_cache,將它們存儲在我的本地變量allKeys,然後同時從_cache刪除所有的密鑰。

但是我想要做到這一點。那麼,什麼想到的是:

Parallel.ForEach(_cache.Select(o => o.Key), key => _cache.Remove(key)); 

但聲明_cache.Select(o => o.Key)會被要求每次循環迭代,因此檢索每個時間不同量元素的(因爲我在同一時間刪除)。

後面的代碼行是否安全?

_cache.Select(o => o.Key)在循環語句中,只調用一次,然後每個迭代使用原始結果,還是在每個迭代步驟中處理?

+1

什麼類型是_cache? – Paddy

+3

在單行中做這件事會有什麼好處? –

+2

_「但是每個循環迭代都會調用_cache.Select(o => o.Key)語句」_ - 你確定嗎? – CodeCaster

回答

4

首先,兩個代碼是相同的。如果您有臨時變量,則沒有區別。

第二:此代碼有缺陷。

  1. LINQ使用延期執行。換句話說,,而迭代allKeys,底層數據 - 在你的情況_cache - 正在迭代。與刪除相結合,這是行不通的。
  2. _cache最有可能是一個正常的字典或類似的東西。換句話說,它不是線程安全的。更新:根據評論,它是ObjectCache類型,該類型確實是線程安全的。所以這個問題不會發生在你的具體情況中。
+0

第一點將取決於數據結構。當然有可能*(但不太可能)有一個支持這一點的數據結構。後者是真正的交易斷路器。充其量,數據結構可以序列化清除,保持安全;它幾乎沒有辦法讓它實際上並行工作。 – Servy

4

正如你所看到的,我在檢索所有_cache鍵,將它們存儲在我的本地變量allKeys

不,你不知道。由於某些稱爲延遲執行的內容,您存儲的所有內容都是獲取所有密鑰的命令。實際上你需要做你認爲你這樣做來兌現這個命令:

VAR allKeys = _cache.Select(O => o.Key).ToList();

那說:你的緩存線程安全嗎?爲什麼它不具有清除方法?獲取所有密鑰並通過使用多線程刪除它似乎是一個不太好的主意。

如果你堅持要擁有這一切在同一行,你可以使用PLINQ:

_cache.Select(o => o.Key).AsParallel().ForAll(key => _cache.Remove(key)); 

但再次:這似乎是一個壞主意。

1

現有的_cache對象的Dispose效率不高,只是重新創建它,而不是單獨刪除每個項目?

保存查詢和循環...

+0

我想過配置它,但是我的緩存是'MemoryCache'類型的,所以根據這篇文章不建議這樣做:[如何清除System.Runtime.Caching.MemoryCache?](http://stackoverflow.com/問題/ 8043381/how-do-i-clear-a-system-runtime-caching-memorycache) –

+0

好的,有趣的,但可能的(也可以參考答案),只需將_cache設置爲新實例就足夠了? – Paddy

0

首先,在遍歷它,這是.Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)做幕後有什麼不能修改的集合。所以這條線

Parallel.ForEach(_cache.Select(o => o.Key), key => _cache.Remove(key)); 

將根本無法正常工作。

你可以試試這個

Parallel.ForEach(_cache.Select(o => o.Key).ToList(), key => _cache.Remove(key)); 

,這將在密鑰的副本。 ObjectCache類型是線程安全的,因爲MemoryCache所以你應該沒問題。

這裏唯一的潛在問題是這個代碼是否在多線程應用程序(如Web應用程序)中。讓多個線程能夠讀取/寫入/從緩存中刪除/從緩存中刪除會導致大量的蠕蟲,並且使用鎖來管理緩存訪問是必需的。