杰瑞科技汇

Flask缓存怎么用?Python缓存方案有哪些?

Of course! Caching is a crucial technique for improving the performance and scalability of web applications. In Flask, caching can significantly reduce the load on your server, your database, and external APIs by storing the results of expensive operations.

Here's a comprehensive guide to using caching in Flask, from the simple built-in cache to more advanced strategies.


The Simplest Way: Flask's Built-in Cache

Flask comes with a simple, in-memory cache. It's great for development and small-scale applications but is not suitable for production in a multi-process environment (like Gunicorn with multiple workers) because each worker has its own separate memory.

How to Use It

  1. Install Flask: (If you haven't already)

    pip install Flask
  2. Create your Flask app and initialize the cache: You need to configure the cache with a CACHE_TYPE. The default is 'SimpleCache', which is the in-memory one.

    from flask import Flask, render_template
    from flask_caching import Cache
    app = Flask(__name__)
    # Configure the cache
    app.config['CACHE_TYPE'] = 'SimpleCache'  # This is the default
    # Optional: Set a default timeout for all cached views (in seconds)
    app.config['CACHE_DEFAULT_TIMEOUT'] = 300 # 5 minutes
    # Initialize the cache extension
    cache = Cache(app)
    @app.route('/')
    @cache.cached(timeout=50)  # Cache this view for 50 seconds
    def index():
        print("This is being executed! (This message should only appear once every 50 seconds)")
        return render_template('index.html', name='World')
    @app.route('/user/<username>')
    @cache.cached(timeout=60, query_string=True) # Cache based on URL query string
    def show_user_profile(username):
        print(f"Fetching profile for {username}...")
        # Imagine this is a slow database query
        user_data = {'name': username, 'id': 123}
        return render_template('profile.html', user=user_data)
    if __name__ == '__main__':
        app.run(debug=True)
    • @cache.cached(timeout=50): This decorator caches the return value of the index function for 50 seconds. The next 49 requests will be served instantly from the cache without executing the function.
    • query_string=True: This is a powerful option. It caches different versions of the view based on the query string. For example, /user/john?view=summary and /user/john?view=detailed would be cached as two separate entries.

Limitations of SimpleCache

  • Not Process-Shared: If you run your app with multiple workers (e.g., gunicorn -w 4 app:app), each worker has its own cache. A request handled by worker 1 won't benefit from the cache of worker 2.
  • Not Persistent: The cache is cleared when the server restarts.

Production-Ready Caches: Memcached and Redis

For production, you need a dedicated, external caching service that all your application workers can access. The two most popular choices are Memcached and Redis.

A. Memcached

Memcached is a high-performance, distributed memory object caching system. It's simple and extremely fast for what it does.

Setup:

  1. Install Memcached on your server:

    • Ubuntu/Debian: sudo apt-get install memcached
    • CentOS/RHEL: sudo yum install memcached
    • macOS (with Homebrew): brew install memcached
    • Then start the service: sudo systemctl start memcached (or memcached -d on older systems).
  2. Install the Python client:

    pip install Flask-Caching python-memcached
  3. Configure your Flask app: Change the CACHE_TYPE to 'Memcached' and provide the server address.

    from flask import Flask
    from flask_caching import Cache
    app = Flask(__name__)
    # Configure for Memcached
    app.config['CACHE_TYPE'] = 'Memcached'
    app.config['CACHE_MEMCACHED_SERVERS'] = ['127.0.0.1:11211'] # Default port
    app.config['CACHE_DEFAULT_TIMEOUT'] = 300
    cache = Cache(app)
    @app.route('/memcached-route')
    @cache.cached(timeout=60)
    def memcached_example():
        print("This slow function is only running once per minute.")
        return "This page is cached by Memcached."
    # ... rest of your app

B. Redis

Redis is an advanced key-value store. It's more than just a cache (it supports data structures like lists, sets, sorted sets) and is often used as a primary database or message broker as well. It's a fantastic choice for caching.

Setup:

  1. Install Redis on your server:

    • Ubuntu/Debian: sudo apt-get install redis-server
    • CentOS/RHEL: sudo yum install redis
    • macOS (with Homebrew): brew install redis
    • Then start the service: sudo systemctl start redis
  2. Install the Python client:

    pip install Flask-Caching redis
  3. Configure your Flask app: Change the CACHE_TYPE to 'Redis' and provide the server URL.

    from flask import Flask
    from flask_caching import Cache
    app = Flask(__name__)
    # Configure for Redis
    app.config['CACHE_TYPE'] = 'Redis'
    app.config['CACHE_REDIS_URL'] = 'redis://localhost:6379/0' # Use DB 0
    app.config['CACHE_DEFAULT_TIMEOUT'] = 300
    cache = Cache(app)
    @app.route('/redis-route')
    @cache.cached(timeout=60)
    def redis_example():
        print("This slow function is only running once per minute.")
        return "This page is cached by Redis."
    # ... rest of your app

Caching Specific Data with cache.get() and cache.set()

Sometimes you don't want to cache an entire view. You might want to cache the result of a database query or an expensive calculation.

from flask import Flask
from flask_caching import Cache
import time
app = Flask(__name__)
app.config['CACHE_TYPE'] = 'Redis'
app.config['CACHE_REDIS_URL'] = 'redis://localhost:6379/0'
cache = Cache(app)
def get_expensive_data():
    print("Performing very expensive calculation...")
    time.sleep(3) # Simulate a slow task
    return {"data": "some very important result"}
@app.route('/data')
def get_data():
    # Try to get the data from the cache
    cached_data = cache.get('expensive_data_key')
    if cached_data is None:
        # If not in cache, get it the expensive way
        cached_data = get_expensive_data()
        # Store it in the cache for 60 seconds
        cache.set('expensive_data_key', cached_data, timeout=60)
        print("Data was not in cache. Calculated and stored.")
    else:
        print("Data was found in cache. Served instantly.")
    return cached_data
if __name__ == '__main__':
    app.run(debug=True)
  • cache.get('key'): Retrieves an item from the cache. Returns None if the key doesn't exist or has expired.
  • cache.set('key', value, timeout=60): Stores an item in the cache with a specific timeout.

Advanced Caching: Memoization with @cache.memoize

This is a decorator for caching the result of a function, not a view. It's perfect for utility functions that are called multiple times with the same arguments.

A key feature is that @cache.memoize automatically uses the function's arguments to create a unique cache key.

from flask import Flask
from flask_caching import Cache
app = Flask(__name__)
app.config['CACHE_TYPE'] = 'SimpleCache' # Works with any cache type
cache = Cache(app)
@cache.memoize(timeout=60) # Cache for 60 seconds
def add_numbers(a, b):
    print(f"Calculating {a} + {b}...")
    return a + b
@app.route('/add/<int:a>/<int:b>')
def add_view(a, b):
    result = add_numbers(a, b)
    return f"The result of {a} + {b} is {result}"
if __name__ == '__main__':
    app.run(debug=True)

If you visit /add/5/10, the function will execute. If you visit /add/5/10 again within 60 seconds, the cached result is returned and the function is not executed. However, visiting /add/3/8 will execute the function again because the arguments are different.


Clearing the Cache

You can programmatically clear the cache.

from flask_caching import make_cache_key
# To clear the entire cache
cache.clear()
# To delete a specific key
cache.delete('my_specific_key')
# To delete keys based on a pattern (Redis only)
# This is very powerful for clearing related caches
# For example, clear all user-related caches
# Note: This requires Redis version 4.0+ for the SCAN command
# or you can use a more manual approach with known keys.
# The `delete_many` method with a pattern is not directly in Flask-Caching,
# but you can access the underlying cache object.
if hasattr(cache.cache, 'delete_many'):
    # This is a conceptual example, actual syntax depends on the cache backend
    cache.cache.delete_many(match='user_profile:*')

Summary: Which Cache to Choose?

Cache Type CACHE_TYPE Best For Pros Cons
SimpleCache 'SimpleCache' Development, single-process apps. No external dependencies. Not for production. Not process-safe.
Memcached 'Memcached' High-traffic websites, simple key-value caching. Extremely fast, simple, distributed. Limited to simple data types (strings, binary).
Redis 'Redis' Production apps, need for advanced features (pub/sub, persistence). Very fast, feature-rich, persistent options, widely used. Slightly more complex setup than Memcached.

Recommendation:

  • For development, stick with the default SimpleCache.
  • For production, Redis is the most popular and robust choice. It's a swiss-army knife that can handle caching and much more. Memcached is also an excellent, high-performance choice if you only need basic caching.
分享:
扫描分享到社交APP
上一篇
下一篇