4

我正在尝试制作一个可与多个线程一起使用的 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()

当然,当我同时向多个线程发送一个装饰有 memo 函数(如this )的函数时,问题就开始了。

如何将备忘录的缓存实现为线程之间的共享对象?

4

1 回答 1

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()

您发布的示例将每个函数的缓存存储在字典中,因此您还需要为每个函数存储一个锁。

但是,如果您在竞争激烈的环境中使用此代码,那么它的效率可能会低得令人无法接受,因为即使线程不计算相同的东西,它们也必须相互等待。您可以通过在缓存中为每个键存储一个锁来改进这一点。但是,您还需要全局锁定对锁存储的访问,否则在创建每个键锁时会出现竞争条件。

于 2012-10-26T05:03:00.573 回答