Sobes.tech
Middle
88
questionbank

Что делать, если тестируемая функция выполняет много времени на повторяющиеся операции внутри нее?

Ответ от нейросети

sobes.tech AI

Использовать кэширование результатов выполнения функции.

Наиболее распространенные подходы в Python:

  • @functools.lru_cache: Встроенный декоратор для кэширования результатов функции на основе недавнего использования (Least Recently Used). Удобен для кэширования результатов функций с детерминированным поведением, зависящим от входных аргументов.

    # Декоратор lru_cache
    import functools
    
    @functools.lru_cache(maxsize=128)
    def expensive_function(n):
        // Имитация дорогостоящей операции
        import time
        time.sleep(1)
        return n * 2
    
    // Первое выполнение (долго)
    result1 = expensive_function(5)
    print(f"Первый вызов с 5: {result1}")
    
    // Второе выполнение (быстро, из кэша)
    result2 = expensive_function(5)
    print(f"Второй вызов с 5: {result2}")
    
  • Ручной кэш (словарь): Подходит, когда требуется более тонкий контроль над кэшированием или когда декоратор lru_cache неприменим (например, для методов объектов или когда аргументы функции не хешируемы).

    // Ручной кэш
    cache = {}
    
    def another_expensive_function(n):
        if n in cache:
            return cache[n]
        else:
            // Имитация дорогостоящей операции
            import time
            time.sleep(1)
            result = n * 3
            cache[n] = result
            return result
    
    // Первое выполнение (долго)
    result3 = another_expensive_function(10)
    print(f"Первый вызов с 10: {result3}")
    
    // Второе выполнение (быстро, из кэша)
    result4 = another_expensive_function(10)
    print(f"Второй вызов с 10: {result4}")
    
  • Внешние системы кэширования: Для распределенных систем или более крупномасштабного кэширования можно использовать внешние системы, такие как Redis или Memcached.

    // Пример использования Redis (псевдокод)
    import redis
    
    r = redis.Redis(host='localhost', port=6379, db=0)
    
    def redis_cached_function(arg):
        cache_key = f"cache:expensive_op:{arg}"
        cached_result = r.get(cache_key)
    
        if cached_result:
            return cached_result.decode('utf-8') // Декодируем байты Redis
        else:
            // Дорогостоящая операция
            result = f"Результат для {arg}"
            r.set(cache_key, result, ex=3600) // Кэшируем на 1 час
            return result
    
    // Использование
    print(redis_cached_function("параметр_1"))
    print(redis_cached_function("параметр_1")) // Получение из Redis
    

Выбор подхода зависит от конкретных требований:

  • @functools.lru_cache - простота, автоматическое управление размером кэша.
  • Ручной кэш - гибкость, контроль.
  • Внешние системы - распределенное кэширование, персистентность.

Перед внедрением кэширования важно убедиться, что функция является детерминированной (возвращает одинаковый результат для одинаковых входных данных) и что затраты на вычисление перевешивают затраты на хранение и извлечение из кэша.