1

我有一個基於Web的訂單系統的項目。鎖字典不斷增長,如何清理的indeas?

  • 項目是非常有限的時間,銷售用於Y小時
  • 每個項目只允許X訂單

爲了保持訂單每件< = X我使用這個鎖定機制。

private static Dictionary<Guid, Object> PurchaseLockDictionary = null; 

private static object GetLock(Guid itemId) 
    { 
     if (!PurchaseLockDictionary.ContainsKey(itemId)) 
     { 
      PurchaseLockDictionary.Add(itemId, new object()); 
     } 
     return PurchaseLockDictionary[itemId]; 
    } 

併購置看起來是這樣的:

public static Order Purchase(Buyer buyer, OrderItem item) 
    { 
     Order order; 
     try 
     { 
      lock (GetLock(item.Id)) 
      { 
       // order stuff like counting current amount of orders, buyer validity etc 
      } 
     } catch (Exception e) { 
      // Exception stuff 
     } 
     return order; 
    } 

現在,我的問題是,如何將我的閉鎖機構(Dictionary對象)從生長出來的比例?目前,我們每週都會重新啓動一次服務器,原因是其他原因,但我不希望代碼依賴這種行爲。

有沒有更適合這種鎖定機制的數據結構?或者,有沒有一種巧妙的方式來查找和清理詞典中的舊條目?想法是非常受歡迎的!

+1

如果這段代碼是從多個線程中調用的(如果不是,那麼根本就不需要任何鎖),那麼你需要圍繞字典本身進行某種大的全局鎖定。如果不是這樣,那麼當多個線程碰到'ContainsKey','Add',索引器等時,運行競爭條件的風險,甚至破壞你的字典。 – LukeH 2011-04-28 14:53:04

+0

這聽起來像你想要使用緩存解決方案,將過期的項目是不經常使用/訪問。如果是這樣,那麼你應該看看System.Runtime.Caching http://msdn.microsoft.com/en-us/library/system.runtime.caching.aspx – 2011-04-28 14:53:06

+0

您是否重用了您在字典中添加的對象進行計數訂購物品的數量還是你使用它只是作爲鎖? – fixagon 2011-04-28 14:54:16

回答

2
using (var locker = new PurchaseLocker(item.Id)) 
{ 
    // order stuff like counting current amount of orders, buyer validity etc 
} 

// ... 

public sealed class PurchaseLocker : IDisposable 
{ 
    private static readonly object _bigLock = new object(); 
    private static readonly Dictionary<Guid, LockToken> _lockMap = new Dictionary<Guid, LockToken>(); 
    private readonly Guid _itemId; 

    public PurchaseLocker(Guid itemId) 
    { 
     _itemId = itemId; 

     LockToken miniLock; 
     lock (_bigLock) 
     { 
      if (!_lockMap.TryGetValue(itemId, out miniLock)) 
      { 
       miniLock = new LockToken(); 
       _lockMap.Add(itemId, miniLock); 
      } 
      miniLock.Count++; 
     } 
     Monitor.Enter(miniLock); 
    } 

    public void Dispose() 
    { 
     lock (_bigLock) 
     { 
      LockToken miniLock = _lockMap[_itemId]; 
      miniLock.Count--; 
      if (miniLock.Count == 0) 
       _lockMap.Remove(_itemId); 

      Monitor.Exit(miniLock); 
     } 
    } 

    private sealed class LockToken 
    { 
     public int Count; 
    } 
} 
+0

這看起來像是一個完美的解決方案。使用真的很漂亮!我爲什麼沒有想到這一點!不影響當前的代碼。實際上可以直接複製粘貼到我的代碼並開始測試! – mofoo 2011-04-29 08:44:24

1

這聽起來像你想使用一個緩存解決方案,這將到期經常訪問的未使用的物品/。如果是這樣,那麼你應該看看System.Runtime.Caching。您可以將項目添加到緩存中,如果您使用的是在多線程程序時,你會遇到麻煩設置了保質政策等

1

Dictionary不是線程安全的。考慮改用ConcurrentDictionary

對於您的項目,我假設你遞增的順序計數每次有人訂單之一。你不能只在Purchase方法從該字典中刪除該項目的訂單數量達到最大值時,或者該項目關閉特殊?

+0

謝謝你指向ConcurrentDictionary的指針! 是的,購買到達X時我可以刪除條目,但在最壞的情況下,每件商品都會被購買X-1次,並且沒有條目被刪除。 – mofoo 2011-04-28 16:00:14

+0

@mofoo:但你說物品有時間限制。所以你應該能夠在物品時間到期後從詞典中刪除物品(即該物品不再銷售)。 – 2011-04-28 16:11:34

+0

的確,我可以有這樣的解決方案..但是之後我需要檢查過期的項目,我什麼時候執行檢查?它會工作,但它會在訂單交易中創造更多的開銷,而不是那個漂亮的代碼。 – mofoo 2011-04-29 08:57:16