2012-10-26 3 views
4

Я пытаюсь создать декоратор memoize, который работает с несколькими потоками.Потокобезопасный декоратор memoize

Я понял, что мне нужно использовать кеш как общий объект между потоками и приобретать/блокировать общий объект. Я, конечно, запуская темы:

for i in range(5): 
      thread = threading.Thread(target=self.worker, args=(self.call_queue,)) 
      thread.daemon = True 
      thread.start() 

где работник:

def worker(self, call): 
    func, args, kwargs = call.get() 
    self.returns.put(func(*args, **kwargs)) 
    call.task_done() 

начинается проблема, конечно же, когда я посылаю функцию украшенную памятки (как this) для многих потоков одновременно.

Как я могу реализовать кеш memo как общий объект среди потоков?

ответ

2

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

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

lock = threading.Lock() 
... 
except KeyError: 
    with lock: 
     if key in self.cache: 
      v = self.cache[key] 
     else: 
      v = self.cache[key] = f(*args,**kwargs),time.time() 

Пример вы вывесили хранит кэш на функцию в словаре, так что вам нужно хранить блокировку каждой функции, а также.

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

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