2013-12-22 2 views
0

Замена значения, связанного с ключом ConcurrentDictionary, блокирует любые операции словаря за пределами этого ключа?Замена операций с разными ключами ConcurrentDictionary на один замок?

EDIT: Например, я хотел бы знать, если один поток будет когда-либо блокировать другой, к тому же, когда ключи сначала добавляются в следующем:

public static class Test { 
    private static ConcurrentDictionary<int, int> cd = new ConcurrentDictionary<int, int>(); 
    public static Test() { 
     new Thread(UpdateItem1).Start(); 
     new Thread(UpdateItem2).Start(); 
    } 
    private static void UpdateItem1() { 
     while (true) cd[1] = 0; 
    } 
    private static void UpdateItem2() { 
     while (true) cd[2] = 0; 
    } 
} 

Первоначально я предполагал его делает, потому что, например, dictionary[key] = value; может ссылаться на ключ, которого пока нет. Однако, работая, я понял, что если добавление необходимо, это может произойти после отдельной эскалации блокировки.

Я разрабатывал следующий класс, но косвенность, предоставляемая классом AccountCacheLock, не нужна, если ответ на этот вопрос (см. Выше) - «нет». На самом деле, все мои собственные блокировки практически не нужны.

// A flattened subset of repository user values that are referenced for every member page access 
public class AccountCache { 

    // The AccountCacheLock wrapper allows the AccountCache item to be updated in a locally-confined account-specific lock. 
    // Otherwise, one of the following would be necessary: 
    // Replace a ConcurrentDictionary item, requiring a lock on the ConcurrentDictionary object (unless the ConcurrentDictionary internally implements similar indirection) 
    // Update the contents of the AccountCache item, requiring either a copy to be returned or the lock to wrap the caller's use of it. 
    private static readonly ConcurrentDictionary<int, AccountCacheLock> dictionary = new ConcurrentDictionary<int, AccountCacheLock>(); 

    public static AccountCache Get(int accountId, SiteEntities refreshSource) { 
     AccountCacheLock accountCacheLock = dictionary.GetOrAdd(accountId, k => new AccountCacheLock()); 
     AccountCache accountCache; 
     lock (accountCacheLock) { 
      accountCache = accountCacheLock.AccountCache; 
     } 
     if (accountCache == null || accountCache.ExpiresOn < DateTime.UtcNow) { 
      accountCache = new AccountCache(refreshSource.Accounts.Single(a => a.Id == accountId)); 
      lock (accountCacheLock) { 
       accountCacheLock.AccountCache = accountCache; 
      } 
     } 
     return accountCache; 
    } 

    public static void Invalidate(int accountId) { 
     // TODO 
    } 

    private AccountCache(Account account) { 
     ExpiresOn = DateTime.UtcNow.AddHours(1); 
     Status = account.Status; 
     CommunityRole = account.CommunityRole; 
     Email = account.Email; 
    } 

    public readonly DateTime ExpiresOn; 
    public readonly AccountStates Status; 
    public readonly CommunityRoles CommunityRole; 
    public readonly string Email; 

    private class AccountCacheLock { 
     public AccountCache AccountCache; 
    } 
} 

Боковой вопрос: есть ли что-то в структуре ASP.NET, которая уже делает это?

+0

На какой точный замок следует полагаться? Я еще не совсем понял, чего вы пытаетесь достичь ... –

+0

Эй, Джон. Я не уверен, что понимаю ваш запрос на разъяснение; Я почти уверен, что этого не хватает, но я не могу понять, что это такое. Я попытаюсь повторить: я хочу заменить элемент в словаре, не блокируя добавление других элементов или блокируя чтение или замену других значений ключа. Нужен ли мне дополнительный блокирующий слой, который я добавил с помощью AccountCacheLock в моем собственном коде выше, или я могу просто вызвать 'ConcurrentDictionary [key] ='? – shannon

+0

В конечном счете, я просто пытаюсь создать кэш для часто используемой учетной записи (и дочерней) информации, указанной в идентификаторе учетной записи.Я был обеспокоен тем, что если я просто попрошу совпадающий словарь заменить элемент, я заблокирую все потоки от использования кеша на время замены. – shannon

ответ

2

Вам не нужно делать какие-либо замки. ConcurrentDictionary должен справиться с этим довольно хорошо.

Боковой вопрос: есть ли что-то в структуре ASP.NET, которая уже делает это?

Конечно. Это не связано конкретно с ASP.NET, но вы можете взглянуть на пространство имен System.Runtime.Caching и, более конкретно, на класс MemoryCache. Он добавляет такие вещи, как истечение срока действия и обратные вызовы в верхней части поточной безопасной хэш-таблицы.

Я не совсем понимаю цель AccountCache, которую вы указали в своем обновленном ответе. Это именно то, что простой слой кеширования дает вам бесплатно.

Очевидно, что если вы планируете использовать приложение ASP.NET в веб-ферме, вам следует рассмотреть некоторые распространенные кеширования, например memcached. Существуют реализации .NET класса ObjectCache поверх протокола memcached.

+0

Я не мог найти 'AccountClass' в моем вопросе. Вы можете иметь в виду 'AccountCache'. Если это так, предполагается, что не только объект Account, но и некоторая связанная информация, рухнула из пары связанных объектов и правил безопасности. Кроме того, предполагается избегать кэширования всего объекта учетной записи, когда очень мало ссылок на свойства учетной записи. Кэширование ненужных свойств (особенно полная иерархия) не только увеличило бы издержки памяти, но, что более важно, увеличило бы частоту, когда элемент был недействителен в простой реализации кеша. Я понял? – shannon

+0

Да, конечно, возможно, что я полностью дублирую функциональность, присутствующую в классе MemoryCache. Я не оспариваю это. Я собираюсь расследовать. – shannon

+1

Извини, мой плохой. Я имел в виду «AccountCache». Если весь объект Account слишком велик для кэширования, подумайте об использовании некоторого представления о нем (модели представления), которое будет кэшироваться с помощью MemoryCache. Кэширование IMHO сложно, и я бы рекомендовал использовать классы, встроенные в фреймворк, вместо того, чтобы пытаться сворачивать свои собственные. –

0

Я также хотел отметить, что я сделал беглый взгляд в ConcurrentDictionary, и похоже, что замены элементов заблокированы ни по отдельному элементу, ни по всему словарю, а скорее к хэшу элемента (т. Е. К объекту блокировки, связанному с словарь «ведро»). Кажется, он разработан так, что первоначальное введение ключа также не блокирует весь словарь, если словарь не нуждается в изменении размера. Я считаю, что это также означает, что одновременно могут возникать два обновления при условии, что они не создают соответствующие хэши.

 Смежные вопросы

  • Нет связанных вопросов^_^