python - 如何结合@singledispatch和@lru_cache?

标签 python annotations generic-programming lru single-dispatch

我有一个像这样的 Python 单调度通用函数:

@singledispatch
def cluster(documents, n_clusters=8, min_docs=None, depth=2):
  ...

它是这样重载的:

@cluster.register(QuerySet)
@lru_cache(maxsize=512)
def _(documents, *args, **kwargs):
  ...

第二个基本上预处理 QuerySet 对象并调用通用 cluster() 函数。 一个QuerySet is a Django object ,但这不应该在这里发挥作用;除此之外,它是可散列的,因此可以与 lru_cache 一起使用。

通用函数无法缓存,因为它接受不可散列的对象(例如列表)作为参数。但是,由于 QuerySet 对象是可散列的,因此可以缓存重载函数。这就是我添加 @lru_cache() 注释的原因。

但是,缓存似乎没有应用:

qs: QuerySet = [...]

start = datetime.now(); cluster(Document.objects.all()); print(datetime.now() - start)               
0:00:02.629259

我希望在实例中发生相同的调用,但是:

start = datetime.now(); cluster(Document.objects.all()); print(datetime.now() - start)               
0:00:02.468675

缓存统计信息证实了这一点:

cluster.registry[django.db.models.query.QuerySet].cache_info()
CacheInfo(hits=0, misses=2, maxsize=512, currsize=2)

更改 @lru_cache@.register 注释的顺序似乎没有什么区别。

This question类似,但答案不适合单个功能级别。

是否有可能在这个级别上组合这两个注释?如果是这样,怎么办?

最佳答案

hash(Document.objects.all()) == hash(Document.objects.all()) 与 Django QuerySet 不一致。

在评估返回的 QuerySet 之前,调用 Document.objects.all() 不会访问数据库。

Pickling is usually used as a precursor to caching

Django docs .

根据您的用例,您可以尝试缓存 QuerySet 的 pickle 或其 query 属性。

@cluster.register(bytes)
@lru_cache(maxsize=512)
def _(documents, *args, **kwargs):
    documents = pickle.loads(documents)
    ...

cluster(pickle.dumps(Document.objects.all()))

cluster(pickle.dumps(Document.objects.all().query))

关于python - 如何结合@singledispatch和@lru_cache?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60415891/

相关文章:

python - 将 openCV 窗口置于前面并关注焦点 macOS

Python 语言环境不适用于 alpine linux

java - 注解和处理器之间的匹配

java - 什么是注解索引?

java - 二元运算符的操作数类型错误 '+'

c# - Linq 表达式 : Create a max query using a generic DbSet

Python Pandas,将 DataFrame 写入固定宽度文件(to_fwf?)

python - 用 cython 包装 C++ 类,让基本示例正常工作

java - JPA:外键注释

C - 通用函数 : swap two items in array