python - 一个线程安全的 memoize 装饰器

标签 python multithreading decorator memoization gil

我正在尝试制作一个适用于多线程的 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/

相关文章:

java - JVM 如何确保新对象内存分配的线程安全

Java 装饰函数

c# - 声明静态成员的类装饰器(例如,对于 log4net)?

c - MPI:Printf 语句未在正确的时间执行

Python:如果在 For 循环中

python - 从 Pandas 中删除重复列读取 excel 数据框

python - 使用私钥在python中简单的加密/解密库

c++ - 如何将线程与容器 C++ 一起使用

python - 使用参数验证 Python 数据转换以获得预期结果

python - 是否可以根据 geopandas 中的属性添加不同的缓冲区?