Словарь блокировок продолжает расти, как очистить? - PullRequest
1 голос
/ 28 апреля 2011

У меня есть система заказов на основе товаров через Интернет.

  • Товары очень ограничены во времени, продаются за Y часов
  • Каждый товар может содержать только X заказов

Для хранения заказов на единицу товара <= X Я использую этот механизм блокировки. </p>

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) от растущих пропорций?В настоящее время мы выполняем еженедельную перезагрузку сервера по другим причинам, но я не хочу, чтобы код полагался на такое поведение.

Существует ли другая структура данных, которая более подходит для этого механизма блокировки?Или есть умный способ найти и очистить старые записи в словаре?Идеи очень приветствуются!

Ответы [ 3 ]

2 голосов
/ 28 апреля 2011
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;
    }
}
1 голос
/ 28 апреля 2011

Если вы используете это в многопоточной программе, у вас будут проблемы.Dictionary не является потокобезопасным.Попробуйте вместо этого использовать ConcurrentDictionary .

Для ваших товаров я предполагаю, что вы увеличиваете количество заказов каждый раз, когда кто-то заказывает его.Разве вы не можете просто заставить метод Purchase удалить элемент из словаря, когда количество заказов этого элемента достигнет максимума, или когда элемент выйдет особенным?

1 голос
/ 28 апреля 2011

Звучит так, как будто вы хотите использовать решение для кэширования, у которого истекают элементы, которые не используются / не используются часто.Если это так, то вам следует взглянуть на System.Runtime.Caching .Вы можете добавлять элементы в кеш, устанавливать политику истечения срока их действия и т. Д.

...