2012-03-20 2 views
1

Я в настоящее время пытаюсь уменьшить количество подобных запросов обрабатываются в бизнес-слое:запросов Кэширования уменьшить обработку (TPL?)

  1. Кэширования запросов метод получает
  2. Performing медленных обработки задач (один раз для всех подобных запросов)
  3. Возврат результат каждого метода запрашивающего вызывает

Things отметить, является то, что:

  • Оригинальные звонки метода не в настоящее время в асинхронном BeginMethod()/EndMethod (IAsyncResult)
  • просит прибыть быстрее, чем время, необходимое для создания выходного
  • Я пытаюсь использовать TPL, где это возможно, поскольку я в настоящее время пытаюсь узнать больше об этой библиотеке

например. Улучшение следующих

byte[] RequestSlowOperation(string operationParameter) 
{ 
    Perform slow task here... 
} 

Любые мысли?

Развейте:

class SomeClass 
{ 
    private int _threadCount; 

    public SomeClass(int threadCount) 
    { 
     _threadCount = threadCount; 
     int parameter = 0; 

     var taskFactory = Task<int>.Factory; 

     for (int i = 0; i < threadCount; i++) 
     { 
      int i1 = i; 

      taskFactory 
       .StartNew(() => RequestSlowOperation(parameter)) 
       .ContinueWith(result => Console.WriteLine("Result {0} : {1}", result.Result, i1));             
     }    
    } 

    private int RequestSlowOperation(int parameter) 
    { 
     Lazy<int> result2; 
     var result = _cacheMap.GetOrAdd(parameter, new Lazy<int>(() => RequestSlowOperation2(parameter))).Value;    
     //_cacheMap.TryRemove(parameter, out result2); <<<<< Thought I could remove immediately, but this causes blobby behaviour 

     return result; 
    } 

    static ConcurrentDictionary<int, Lazy<int>> _cacheMap = new ConcurrentDictionary<int, Lazy<int>>(); 
    private int RequestSlowOperation2(int parameter) 
    { 
     Console.WriteLine("Evaluating"); 
     Thread.Sleep(100);    
     return parameter; 
    } 
} 

ответ

1

Вот быстрый, безопасный и ремонтопригодны способ сделать это:

static var cacheMap = new ConcurrentDictionary<string, Lazy<byte[]>>(); 
byte[] RequestSlowOperation(string operationParameter) 
{ 
    return cacheMap.GetOrAdd(operationParameter,() => new Lazy<byte[]>(() => RequestSlowOperation2(operationParameter))).Value; 
} 

byte[] RequestSlowOperation2(string operationParameter) 
{ 
    Perform slow task here... 
} 

Это будет выполнять RequestSlowOperation2 максимум один раз за ключ. Помните, что память, хранящаяся в словаре, никогда не будет выпущена.

Делегат пользователя, переданный в ConcurrentDictionary, не выполняется под блокировкой, что означает, что он может выполняться несколько раз! Мое решение позволяет создавать несколько лени, но только один из них будет опубликован и материализован.

Что касается блокировки: это решение будет принимать блокировки, но это не имеет значения, потому что рабочие предметы намного дороже, чем операции блокировки (несколько).

+1

Почему вы даже используете 'Lazy ' здесь? Я думаю, что делегат, переданный 'GetOrAdd()', не будет выполнен, если значение для этого ключа уже существует. – svick

+1

Следует отметить, что это не исключает блокировку, вы просто используете структуру данных, которая скрывает сложность от вас (ConcurrentDictionary). –

+0

Ваше предложение довольно приятно usr. Я просто проверяю, как очистить этот словарь в моем сценарии. Спасибо за ваш отзыв. – Westy

1

Честно говоря, использование TPL как технологии здесь не очень важно, это просто прямо проблема параллелизм. Вы пытаетесь защитить доступ к общему ресурсу (кэшированные данные), и для этого единственный подход - это для блокировки. Либо это, либо, если запись в кеше еще не существует, вы можете разрешить всем входящим потокам ее генерировать, а затем последующие пользователи получают выгоду от кэшированного значения после его сохранения, но в этом мало значения, если ресурс медленный/дорогостоящий для генерации и кеш.

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

+0

Спасибо, Дрю. Я обновил свой предыдущий вопрос, чтобы удалить «исключить блокировку». – Westy

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