我正在尝试制作一个适用于多线程的 memoize 装饰器。
我明白了,我需要使用缓存作为线程之间的共享对象,并获取/锁定共享对象。我当然要启动线程:
for i in range(5):
thread = threading.Thread(target=self.worker, args=(self.call_queue,))
thread.daemon = True
thread.start()
worker 在哪里:
def worker(self, call):
func, args, kwargs = call.get()
self.returns.put(func(*args, **kwargs))
call.task_done()
当然,当我同时向多个线程发送一个装饰有备忘录函数(如 this )的函数时,问题就开始了。
如何将备忘录的缓存实现为线程间的共享对象?
最佳答案
最直接的方法是对整个缓存使用一个锁,并要求对缓存的任何写入都首先获取锁。
在您发布的示例代码中,在第 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()
您发布的示例在字典中为每个函数存储一个缓存,因此您还需要为每个函数存储一个锁。
但是,如果您在高度争议的环境中使用此代码,它的效率可能会低得令人无法接受,因为线程必须相互等待,即使它们计算的不是同一件事。您可以通过在缓存中为每个键存储一个锁来改进这一点。不过,您还需要全局锁定对锁存储的访问,否则在创建每键锁时会出现竞争条件。
关于python - 一个线程安全的 memoize 装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13079842/