Sobes.tech
Back to questions
Middle
109
questionbank

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

Answer from AI

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 - простота, автоматическое управление размером кэша.
  • Ручной кэш - гибкость, контроль.
  • Внешние системы - распределенное кэширование, персистентность.

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