我正在尝试制作一个适用于多个线程的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)修饰的函数同时发送到许多线程时,问题就开始了。
如何将备忘录的缓存实现为线程间的共享对象?
答案 0 :(得分: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()
您发布的示例将每个函数的缓存存储在字典中,因此您还需要为每个函数存储一个锁。
如果你在一个备受争议的环境中使用这个代码,那么它可能是无法接受的低效率,因为线程必须等待彼此,即使它们没有计算相同的东西。您可以通过在缓存中存储每个锁的锁来改进这一点。但是,您还需要全局锁定对锁存储的访问,否则在创建每个密钥锁时会出现竞争条件。