Потоки последствий общей идиомы кеширования - PullRequest
0 голосов
/ 20 августа 2011

Распространенная идиома кэширования - проверять наличие элемента в кэше, извлекать, если присутствует, или создавать, если нет.

Не создает ли это условие, при котором контекст переключается с Thread 1 наThread 2 происходит в месте с комментариями, значение, добавленное в кэш, может быть немедленно перезаписано, когда произойдет переключение контекста обратно на Thread 1?Недостатком является то, что calculateFooBar() теперь вызывается дважды для вычисления одного и того же кэшированного элемента.Является ли это просто принятым «незначительным» следствием этой простой реализации кэширования.Критическая секция обычно не используется, потому что это добавит накладные расходы ко всем GetOrCreate методам?

Редактировать: _cache - это ссылка на общий кэш данных (например, кэш данных ASP.NET).

//not real C#
class FooBarDictionary
{
    ...

    FooBar GetOrCreate(string key)
    {
        FooBar fooBar;

        if (!_cache.TryGetValue(key, out fooBar))
        {
            fooBar = calculateFooBar(); //context switch occurs here
            fooBars.Add(key, fooBar);
        }

        return fooBar;
    }
}

Ответы [ 3 ]

1 голос
/ 20 августа 2011

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

ConcurrentDictionary <> будет хорошим выбором для такого контейнера "nolock", как уже упоминалось другими.

1 голос
/ 20 августа 2011

Мы используем в нескольких сценариях некоторое пользовательское кэширование ... новое Concurrent* - Коллекции в .NET 4 очень хорошо подходят для таких имплементаций ...

Если foobars является ConcurrentDictionary<string, FooBar>, вы можете сделать что-то вроде:

return foobars.GetOrAdd (key, (k) => calculateFooBar() );

Этот код заменит все тело вашего примера метода GetOrCreate.

Подробнее см. http://geekswithblogs.net/BlackRabbitCoder/archive/2011/02/17/c.net-little-wonders-the-concurrentdictionary.aspx

1 голос
/ 20 августа 2011

Все будет зависеть от того, что это за переменная _cache: ее тип и область действия. Если это статическая переменная и не безопасна для потоков, такая как Dictionary<TKey, TValue>, вам необходимо синхронизировать доступ к ней с помощью lock. В .NET 4.0 у вас есть тип ConcurrentDictionary<TKey, TValue>, который позволяет достигать подобных результатов потокобезопасным способом. Ваш код в порядке, но без lock нет никакой гарантии, что вычисление не будет выполнено дважды для одного и того же ключа за очень короткий промежуток времени.

Вы можете взглянуть на следующий пост в блоге для хорошей реализации этого шаблона. Также, если вы используете .NET 4.0, вы можете использовать новую сборку System.Runtime.Caching .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...