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