Обновить
12
0

Пользователь

Отправить сообщение

Если честно, я скептически отношусь к keydb, возможно из-за того что не встречал серьезных проблем с redis и его всегда хватало.
Насчет поддержки других хранилишь: думал про memcached конечноже, но решил подождать пока кому-нибудь понадобится так как он стремительно теряет свою популярность. А других претендентов пока не вижу.

Хотелось бы большей деталей: к чему эта гонка может привести?
Но могу сказать, что в работе с кешом обычно вопрос гонки важен в случае высокой нагрузки на кеш, которая может привести к cache stampede: когда есть кеш в высоким рейтом вызова и вдруг происходит инвалидация, которая приводит к паралеьному пересчету данных для кэша. Можно про него еще вот тут еще почитать.

Для зашиты от этой проблемы есть в библиотеке несколько решений:

1)cache.early декоратор, который кроме обычного ttl имеет второй ttl - ранней экпирации, после которого кэш обновится в бекграунде, причем перерасчет будет гарантировано сделан 1 раз, достигается засчет атомарности операции incr если мы храним кеш в redis. Можно сказать, что это аналог XFetch алгоритма.

2) cache.hit декоратор, который с указанием update_after будет действовать также как cache.early, отлько ориентиром для раннего обновления кеша будет количество хитов.

3) cache.locked декоратор, который поставит лок на исполнении декорируемой функции - таким образом при совмещении 2 декораторов можно будет гарантировать что паралельного перерасчета кеша не будут

@cache(ttl="10m")
@cache.locked(ttl="5s")
async def func():

Что насчёт возможности декорирования методов класса?

Если вы насчет моей библиотки то их возможно декорировать. Есть маленькая проблема: библиотека дает возможность не указывать ключ для кеша и тогда он будет сгенерирован самой библиотекой

class MyClass:

    @cache(ttl="10s")
    async def method(self, arg):
        ...

в таком случае ключ сформируется не совсем валидный: main:method:self:<main.myclass object at 0x10545eeb0>:arg:test

Согласен, что такое поведение не комельфо, но когда разработчик декорирует метод, то не ясно, хочет ли он кеш для класса или для обьекта этого класса. Поэтому правильней будет если разработчик будет указывать конкретный шаблон для ключа:

    @cache(ttl="10s", key="method:{self.id}:{arg}")
    async def method(self, arg):
        ...
# vs
    @cache(ttl="10s", key="method:{arg}")
    async def method(self, arg):
        ...

Про args/kwargs и производительность всего этого каверзных вопросов не задаю) Я сам очень скрипел зубами, если что-то лишнее приходилось делать в рантайме, ибо удобство шло в конфликт с производительностью

Да я понимаю о чем вы, о необходимости получать сигнатуру через интроспекцию? - это дорого, но есть же кэш )

@lru_cache(maxsize=100)
def _get_func_signature(func):
    return inspect.signature(func)

Ну я бы понимал ваше негодование если бы статья называлась "Почему вам стоит использовать async", но у меня статья про другое. Я лиш хотел обозначить свою мотивацию выбора.

Сам писал такие обертки и работал с чужими, сам делал баги и покрывал эти обертки тестами - в результат куча кода, который надо поддерживать. Зачем если можно использовать готовое? Именно в результате осознания этого решил вынести это в библиотеку, о которой в последней части статьи идет речь.

Простите, не хотел никого обидеть, когда писал свое видение такой дикой популярности использования async/await в приложениях.

А вот как раз реализации, описанные в статье имею меньший потенциал, так как для части людей они будут избыточны, а для другой не достаточно гибки и производительны.

А можете пояснить почему они будут избыточны? А для других недостаточно производительны?

Информация

В рейтинге
Не участвует
Работает в
Зарегистрирован
Активность