3

我有一个像这样的 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 是一个 Django 对象,但它不应该在这里发挥作用;除了它是可散列的,因此可以与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注释的顺序似乎没有什么区别。

这个问题类似,但答案不适合单个功能级别。

甚至可以在这个级别上结合这两个注释吗?如果是这样,怎么做?

4

1 回答 1

0

hash(Document.objects.all()) == hash(Document.objects.all())对于 Django 不一致QuerySet

在计算返回值之前,调用Document.objects.all()不会命中数据库。QuerySet

酸洗通常用作缓存的前兆

Django 文档

根据您的用例,您可以尝试缓存 theQuerySet或其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))
于 2020-03-05T12:27:23.590 回答