DEV Community

Cover image for 7 Python Caching Strategies That Boost Application Performance by 70%
Nithin Bharadwaj
Nithin Bharadwaj

Posted on

7 Python Caching Strategies That Boost Application Performance by 70%

As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!

Caching significantly boosts application performance by keeping frequently used data in quick-access storage. This approach cuts latency, lessens database strain, and creates smoother user experiences. I've implemented various caching strategies across projects, each with distinct trade-offs between speed, freshness, and complexity.

Python's functools.lru_cache handles in-memory memoization effortlessly. This decorator automatically caches function outputs and evicts least recently used items when limits are reached. During a recent optimization project, I used it to avoid recalculating resource-intensive transformations:

from functools import lru_cache
import hashlib

@lru_cache(maxsize=1024)
def generate_content_hash(content):
    print("Processing large content batch...")
    return hashlib.sha256(content.encode()).hexdigest()

# Initial processing
print(generate_content_hash("PythonCachingStrategies"))  

# Subsequent identical calls skip computation
print(generate_content_hash("PythonCachingStrategies"))
Enter fullscreen mode Exit fullscreen mode

Time-based expiration ensures cached data stays relevant. By pairing values with timestamps, we automatically refresh stale entries. I often use this for API data that updates periodically:

from datetime import datetime, timedelta

stock_cache = {}
CACHE_TTL = timedelta(seconds=30)

def get_live_stock_price(symbol):
    cached_entry = stock_cache.get(symbol)
    now = datetime.now()

    if cached_entry and now - cached_entry['timestamp'] < CACHE_TTL:
        return cached_entry['value']

    # Simulate API call
    live_price = f"${75 + hash(symbol) % 10}"  
    stock_cache[symbol] = {'value': live_price, 'timestamp': now}
    print(f"Fetched fresh price for {symbol}")
    return live_price

# First call hits API
print(get_live_stock_price("PYPL"))  

# Subsequent calls within 30 seconds use cache
print(get_live_stock_price("PYPL"))
Enter fullscreen mode Exit fullscreen mode

Redis enables distributed caching across multiple application instances. Its key-value store with expiration works well for shared data. In a microservices project, we reduced database hits by 70% using this pattern:

import redis
import json

redis_client = redis.Redis(host='redis-host', port=6379)

def cache_user_profile(user_id, profile_data):
    redis_client.setex(
        f"user:{user_id}", 
        timedelta(hours=1),
        json.dumps(profile_data)
    )

def get_cached_profile(user_id):
    cached = redis_client.get(f"user:{user_id}")
    return json.loads(cached) if cached else None
Enter fullscreen mode Exit fullscreen mode

Cache stampedes occur when multiple requests miss simultaneously, causing redundant heavy computations. Locking mechanisms prevent this. I implemented thread locks for a high-traffic web service:

import threading

price_cache = {}
cache_lock = threading.Lock()

def get_product_price(product_id):
    # Check cache without lock first
    if product_id in price_cache:
        return price_cache[product_id]

    with cache_lock:
        # Double-check after acquiring lock
        if product_id in price_cache:
            return price_cache[product_id]

        print(f"Computing price for {product_id}...")
        result = complex_pricing_calc(product_id)
        price_cache[product_id] = result
        return result
Enter fullscreen mode Exit fullscreen mode

Database caching stores query results to avoid repetitive SQL execution. SQLAlchemy plugins simplify this. For an e-commerce platform, we cached product listings:

from sqlalchemy_cache import CachedQuery

class ProductService:
    @CachedQuery(cache_time=600)  # 10 minutes
    def get_featured_products(self):
        return self.session.query(Product).filter(
            Product.featured == True
        ).all()
Enter fullscreen mode Exit fullscreen mode

CDNs accelerate static content delivery globally. Automated cache purging keeps content fresh after updates. Our deployment pipeline includes this CDN refresh step:

import os
import requests

def invalidate_cdn_paths(paths):
    response = requests.post(
        "https://api.cdn.example/purge",
        headers={"API-Key": os.getenv("CDN_KEY")},
        json={"paths": paths}
    )
    response.raise_for_status()
    print(f"Invalidated {len(paths)} CDN paths")

# After updating CSS
invalidate_cdn_paths(["/static/main.css"])
Enter fullscreen mode Exit fullscreen mode

Cache warming preloads anticipated data during off-peak hours. Scheduled jobs populate caches before traffic spikes. We use this for morning rush-hour preparation:

from apscheduler.schedulers.blocking import BlockingScheduler

def warm_popular_caches():
    for product_id in get_trending_products():
        get_product_details(product_id)  # Caches results

scheduler = BlockingScheduler()
scheduler.add_job(warm_popular_caches, 'cron', hour=4)  # 4 AM daily
scheduler.start()
Enter fullscreen mode Exit fullscreen mode

Each technique requires balancing factors like data volatility and access frequency. Simple in-memory caching works for single-process applications, while Redis scales horizontally. Time-based expiration suits predictable data cycles, whereas locking mechanisms protect against thundering herds. CDNs excel for static assets but demand explicit cache invalidation. Warming strategies optimize startup performance but need accurate usage prediction.

During implementation, monitor hit ratios and latency metrics. I use Redis' INFO stats command and Python's cachetools statistics to measure effectiveness. Adjust cache sizes and durations based on actual usage patterns rather than assumptions. Remember that caching introduces consistency challenges—establish clear invalidation workflows for critical data.

📘 Checkout my latest ebook for free on my channel!

Be sure to like, share, comment, and subscribe to the channel!


101 Books

101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.

Check out our book Golang Clean Code available on Amazon.

Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!

Our Creations

Be sure to check out our creations:

Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools


We are on Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Top comments (0)