Как совместить @singledispatch и @lru_cache? - PullRequest
3 голосов
/ 26 февраля 2020

У меня есть Python функция single-dispatch generi c, подобная этой:

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

Она перегружена так:

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

Вторая в основном предварительно обрабатывает QuerySet объект и вызывает обобщенную функцию c cluster(). QuerySet является Django объектом , но это не должно играть здесь никакой роли; кроме того факта, что она является хешируемой и, следовательно, пригодной для использования с lru_cache.

Функция generi c не может быть кэширована, поскольку она принимает непригодные объекты, такие как списки, в качестве аргументов. Однако функция перегрузки может быть кэширована, потому что объект 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, похоже, не имеет значения .

Этот вопрос аналогичен, но ответ не соответствует уровню отдельных функций.

Возможно ли даже объединить эти две аннотации на этом уровне? Если да, то как?

1 Ответ

0 голосов
/ 05 марта 2020

hash(Document.objects.all()) == hash(Document.objects.all()) не согласовано для Django QuerySet.

Вызов Document.objects.all() не попадет в базу данных, пока не будет возвращено QuerySet.

Пиклинг обычно используется в качестве предшественника для кэширования

Django документов .

В зависимости от вашего варианта использования вы можете попробовать кэшировать рассол QuerySet или его атрибут 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))
...