2014-04-21 53 views
1

我試圖在一個MemoryCache對象中緩存一個昂貴函數的結果。使用對象散列代碼作爲內存緩存鍵是否有意義?

的的MemoryCache需要一個密鑰是一個字符串,所以我想知道,如果它是有效的做到以下幾點:

string key = Char.ConvertFromUtf32(myObject.GetHashCode()); 
if (!_resourceDescriptionCache.Contains(key)) 
{ 
    _resourceDescriptionCache[key] = ExpensiveFunction(myObject); 
} 
return (string)_resourceDescriptionCache[key]; 

它使用一個UTF32字符作爲一個潛在的大緩存鍵的感覺奇。

+0

我得到一個錯誤UTF32值必須是0x000000處,並在0x10FFFF之間,所以我想我不能這樣只是轉換一個Int32爲char。 – Alain

+1

並非每個32位值都代表有效的UTF32代碼點。簡單,不是最快但體面有效的將是使用散列碼的十六進制表示。從內存中,'myObject.GetHashCode()。ToString(「X」)'。 –

+0

謝謝大家,非常有幫助的意見 – Alain

回答

2

這取決於。

有些情況下使用GetHashCode()方法可能會導致不正確的行爲很多情況下:

的哈希代碼適用於那些基於哈希表集合高效插入和查找。哈希碼不是一個永久值。出於此原因:

  • 不要序列化哈希碼值或將它們存儲在數據庫中。
  • 不要使用哈希代碼作爲從鍵控集合中檢索對象的鍵。
  • 不要在應用程序域或進程中發送哈希碼。在某些情況下,散列碼可以基於每個進程或每個應用程序域來計算。

http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

如果內存緩存發生(或可以在將來發生)比調用它的代碼不同的進程或應用程序域,你失敗的第三個條件。

使用單個UTF32字符作爲潛在大型緩存的關鍵字時感覺很奇怪。

如果你正在緩存足夠的東西,由於Birthday Problem,32位散列的衝突率可能會不舒服地高。

當緩存數以千萬計的東西時,我使用了一個名爲City Hash(由Google創建,開源)的64位散列,取得了很好的成功。您也可以使用Guid,但與64位散列值相比,GUID的內存維護密鑰是兩倍。

+1

這是一個很好的觀點。我違反了規則#2 - 使用哈希碼作爲集合的關鍵。現在我堅持不知道如何製作一個便宜的緩存密鑰。例如,序列化對象將會太昂貴。 – Alain

+0

ToHashCode()如何實現?據推測,它行爲應該是獨特的(足夠的)財產或財產的組合。您可以通過連接這些屬性的字符串表示來構建您的字符串鍵。 –

+0

不幸的是,這個類實際上處理對象類型,所以'GetHashCode()'是以對象實現它的方式實現的。如果類型拋棄了它的'GetHashCode()'方法,並且存在衝突,那麼即使衝突產生了不同的結果,衝突也會共享相同的「ExpensiveFunction(object)」值(就像序列化程序)。我盡我所能實際使用'鍵= myObject.GetType()+ Char.ConvertFromUtf32這種效果隔離(myObject.GetHashCode());' – Alain

-1

內存緩存由正常的C#字典支持。它確實沒有什麼不同,除了它提供了到期的事實

碰撞的機會是2^32,這是一個整數的大小。即使你碰到碰撞,字典也有安全措施(通過在碰撞時使用Equals)

編輯:只有當字典被賦予未改變的密鑰(例如:字典())。在這種情況下,由於MemoryCache使用字符串,因此不會進行衝突檢測。

+0

'潛在的大緩存'=潛在的高衝突率http://en.wikipedia.org/wiki/Birthday_problem –

+2

字典中的衝突使用更昂貴的Equals方法解決。當使用散列碼作爲字典散列衝突的關鍵時,會導致不正確的行爲,而不僅僅是更昂貴的計算。這是一個巨大的差異。 – Servy

+0

在提供的代碼示例中,它使用object.GetHashCode(),它可能非常獨特。而且,如果它有幾百萬個鍵,那麼它可能會很大,但字典仍然可以處理它;畢竟有大約42億個可能的鑰匙。生日問題不適用,除非自定義哈希生成器實現,只生成有限的密鑰集。 – Dan

1

哈希碼可能發生碰撞。 return 0;GetHashCode的有效實施。多個鍵將共享一個不是你想要的緩存槽......你會混淆物體。

如果您的代碼不適用於return 0;作爲GetHashCode的實現,那麼您的代碼已損壞。

選擇一個更好的緩存鍵。

+0

如何:'鍵= myObject.GetType()+ Char.ConvertFromUtf32(myObject.GetHashCode());',這樣類型的正確實施'的GetHashCode()'不受故意實施失敗的類型影響? – Alain

+0

對於某些上下文,'ExpensiveFunction()'是一個序列化器,它反映了對象在一個「瀏覽器」窗口中預覽其內容。對我來說,每個對象都有一個正確的「預覽」並不重要,更重要的是我不會浪費太多資源,每次在對象瀏覽器中出現每個對象時都會重新序列化它們。 – Alain

+1

(在之前的評論中,我誤解了你)。但是,你認爲'myObject.GetHashCode()'是一個唯一的鍵。如果這實際上是100%的情況下,那麼這將起作用。 「對我來說,每件物品都有一個正確的」預覽「 - 對你來說不那麼重要 - 那麼你的方法就會奏效。即使是有損緩存鍵也沒問題。我不完全理解序列化的註釋,但也許你可以散列序列化表示的前32個字節並將其用作關鍵字。 – usr

相關問題