Python中緩存入門實戰(zhàn)之核心概念與用法詳解
緩存是提升程序性能的關鍵技術——將頻繁訪問的「計算結果/數(shù)據(jù)」臨時存儲在高速介質(如內(nèi)存)中,避免重復計算/重復查詢(如數(shù)據(jù)庫、API),從而大幅降低響應時間。以下是 Python 緩存的入門指南,涵蓋核心概念、常用實現(xiàn)方式和實戰(zhàn)案例。
一、緩存的核心概念
1. 核心目標
減少「高耗時操作」的執(zhí)行次數(shù)(如數(shù)據(jù)庫查詢、復雜計算、網(wǎng)絡請求),用空間換時間。
2. 關鍵術語
- 緩存鍵(Key):唯一標識緩存數(shù)據(jù)的索引(如函數(shù)參數(shù)、請求URL);
- 緩存值(Value):存儲的目標數(shù)據(jù)(如查詢結果、計算結果);
- 過期時間(TTL):緩存數(shù)據(jù)的有效期,避免數(shù)據(jù)過期;
- 緩存失效:緩存數(shù)據(jù)與源數(shù)據(jù)不一致(需設計失效策略,如過期、更新后主動刪除);
- 緩存命中率:命中緩存的請求數(shù) / 總請求數(shù)(越高性能越好)。
3. 適用場景
- 頻繁調(diào)用的純函數(shù)(輸入固定則輸出固定);
- 數(shù)據(jù)庫/Redis/API 等外部資源的重復查詢;
- 復雜計算(如數(shù)據(jù)統(tǒng)計、機器學習模型推理);
- Web 服務的接口響應(如接口返回的靜態(tài)數(shù)據(jù))。
二、Python 緩存的常用實現(xiàn)方式
1. 方式1:手動實現(xiàn)緩存(字典)
最簡單的緩存方式,用 Python 字典存儲鍵值對,適合小型腳本/簡單場景。
示例:緩存斐波那契數(shù)列計算(避免重復遞歸)
# 手動緩存字典
fib_cache = {}
def fibonacci(n):
if n in fib_cache: # 命中緩存,直接返回
return fib_cache[n]
if n <= 1:
result = n
else:
result = fibonacci(n-1) + fibonacci(n-2) # 未命中,計算后存入緩存
fib_cache[n] = result
return result
# 測試:首次計算n=30(耗時),后續(xù)直接取緩存
print(fibonacci(30)) # 首次計算,存入緩存
print(fibonacci(30)) # 命中緩存,瞬間返回
優(yōu)缺點
- 優(yōu)點:極簡、無依賴、靈活;
- 缺點:無過期時間、線程不安全、內(nèi)存占用無限制(易內(nèi)存泄漏)、程序重啟后緩存丟失。
2. 方式2:functools.lru_cache(裝飾器,Python 內(nèi)置)
Python 標準庫 functools 提供的「最近最少使用(LRU)」緩存裝飾器,專為函數(shù)緩存設計,自動管理緩存生命周期。
基礎用法:緩存函數(shù)返回值
from functools import lru_cache
# @lru_cache 裝飾器:緩存函數(shù)調(diào)用結果
# maxsize:緩存最大條目數(shù)(None 表示無限制),typed=True 區(qū)分不同類型參數(shù)(如 1 和 1.0)
@lru_cache(maxsize=None, typed=False)
def calculate_square(x):
print(f"計算 {x} 的平方(未命中緩存)")
return x * x
# 測試
print(calculate_square(5)) # 未命中,執(zhí)行函數(shù)并緩存
print(calculate_square(5)) # 命中緩存,直接返回
print(calculate_square(10)) # 未命中,執(zhí)行并緩存
# 查看緩存信息
print(calculate_square.cache_info()) # CacheInfo(hits=1, misses=2, maxsize=None, currsize=2)
# 清空緩存
calculate_square.cache_clear()
進階:緩存帶參數(shù)的數(shù)據(jù)庫查詢模擬
from functools import lru_cache
# 模擬數(shù)據(jù)庫查詢(高耗時操作)
def query_db(user_id):
print(f"查詢數(shù)據(jù)庫:user_id={user_id}")
return {"id": user_id, "name": f"User{user_id}", "age": 20 + user_id}
# 緩存查詢結果(注意:裝飾器僅緩存可哈希參數(shù),列表/字典需轉為元組/凍結集合)
@lru_cache(maxsize=100)
def get_user(user_id):
return query_db(user_id)
# 測試
print(get_user(1)) # 未命中,查詢數(shù)據(jù)庫
print(get_user(1)) # 命中緩存,直接返回
print(get_user(2)) # 未命中,查詢數(shù)據(jù)庫
優(yōu)缺點
- 優(yōu)點:內(nèi)置無需安裝、自動管理緩存(LRU 淘汰策略)、支持緩存清空/信息查看;
- 缺點:無過期時間、僅支持函數(shù)緩存、程序重啟后緩存丟失、不支持分布式(僅進程內(nèi))。
3. 方式3:第三方庫(cachetools)—— 支持更多緩存策略
cachetools 是 Python 第三方緩存庫,擴展了 lru_cache 的能力,支持 TTL(過期時間)、LFU(最少使用)、FIFO(先進先出)等策略。
步驟1:安裝
pip install cachetools
步驟2:實戰(zhàn):帶過期時間的緩存
from cachetools import TTLCache, cached
# 定義緩存規(guī)則:最大容量100,過期時間10秒(TTL)
cache = TTLCache(maxsize=100, ttl=10)
# 裝飾器綁定緩存規(guī)則
@cached(cache)
def get_weather(city):
# 模擬調(diào)用天氣API(高耗時)
print(f"調(diào)用天氣API:{city}")
return {"city": city, "temperature": 25, "time": "2025-11-25"}
# 測試
print(get_weather("北京")) # 未命中,調(diào)用API
print(get_weather("北京")) # 命中緩存(10秒內(nèi))
# 10秒后再次調(diào)用:緩存過期,重新調(diào)用API
支持的緩存策略
| 策略 | 說明 | 適用場景 |
|---|---|---|
| TTLCache | 帶過期時間的LRU | 需定期更新數(shù)據(jù)(如天氣) |
| LRUCache | 最近最少使用淘汰 | 通用場景 |
| LFUCache | 最少使用淘汰 | 訪問頻率不均的場景 |
| FIFOCache | 先進先出淘汰 | 順序訪問的場景 |
4. 方式4:分布式緩存(Redis)—— 跨進程/跨機器共享
以上方式均為「進程內(nèi)緩存」(僅當前程序可用),若需多進程/多機器共享緩存,需用 Redis(高性能鍵值數(shù)據(jù)庫)。
步驟1:安裝依賴
# 安裝redis驅動 pip install redis
步驟2:啟動Redis(本地/遠程)
- 本地安裝
- 測試可用:
redis-cli ping→ 返回PONG。
步驟3:Python 操作 Redis 緩存
import redis
import time
# 連接Redis(本地默認端口6379,無密碼)
r = redis.Redis(
host="localhost",
port=6379,
password="", # 若有密碼請?zhí)顚?
db=0, # 選擇數(shù)據(jù)庫0
decode_responses=True # 自動將字節(jié)轉為字符串
)
# 封裝緩存函數(shù)
def get_data_from_cache(key, ttl=60):
"""從Redis獲取緩存,無則返回None"""
return r.get(key)
def set_data_to_cache(key, value, ttl=60):
"""存入Redis緩存,設置過期時間(秒)"""
r.setex(key, ttl, value)
# 模擬業(yè)務函數(shù):查詢用戶信息
def get_user_info(user_id):
# 先查緩存
cache_key = f"user:{user_id}"
cache_data = get_data_from_cache(cache_key)
if cache_data:
print(f"命中緩存:{cache_key}")
return cache_data
# 緩存未命中,查詢數(shù)據(jù)庫(模擬)
print(f"查詢數(shù)據(jù)庫:{cache_key}")
db_data = f"User {user_id} Info"
# 存入緩存,過期時間60秒
set_data_to_cache(cache_key, db_data, ttl=60)
return db_data
# 測試
print(get_user_info(1001)) # 未命中,查數(shù)據(jù)庫并緩存
print(get_user_info(1001)) # 命中緩存
time.sleep(61) # 等待緩存過期
print(get_user_info(1001)) # 緩存過期,重新查詢
優(yōu)缺點
- 優(yōu)點:分布式共享、支持過期時間、持久化、高可用;
- 缺點:需部署Redis服務、有網(wǎng)絡開銷、增加系統(tǒng)復雜度。
三、緩存的最佳實踐
1. 選擇合適的緩存粒度
- 細粒度:緩存單個數(shù)據(jù)(如單個用戶信息),命中率高,失效影響??;
- 粗粒度:緩存聚合數(shù)據(jù)(如所有用戶列表),命中率低,失效影響大。
2. 設置合理的過期時間
- 靜態(tài)數(shù)據(jù)(如省份列表):過期時間設為幾小時/幾天;
- 動態(tài)數(shù)據(jù)(如用戶余額):過期時間設為幾秒/幾分鐘;
- 實時性要求高的數(shù)據(jù)(如秒殺庫存):盡量不緩存,或緩存時間極短。
3. 避免緩存穿透
問題:查詢不存在的數(shù)據(jù)(如 user_id=-1),緩存永遠不命中,導致每次都查數(shù)據(jù)庫,壓垮數(shù)據(jù)庫。
解決方案:緩存空值(如 r.setex("user:-1", 60, "null")),并設置短過期時間。
4. 避免緩存雪崩
問題:大量緩存同時過期,導致大量請求直接打向數(shù)據(jù)庫。
解決方案:
- 過期時間加隨機值(如
ttl=60 + random.randint(0, 10)); - 分布式緩存集群(如Redis集群);
- 數(shù)據(jù)庫加限流/熔斷(如
ratelimit庫)。
5. 緩存更新策略
- 寫穿(Write-Through):更新數(shù)據(jù)庫后立即更新緩存;
- 寫回(Write-Back):先更新緩存,異步更新數(shù)據(jù)庫(適合高并發(fā)寫);
- 失效優(yōu)先:更新數(shù)據(jù)庫后刪除緩存,下次查詢時重新加載(最簡單)。
四、緩存庫選型建議
| 場景 | 推薦方案 |
|---|---|
| 簡單函數(shù)緩存(單進程) | functools.lru_cache |
| 帶過期時間的函數(shù)緩存 | cachetools.TTLCache |
| 分布式/跨進程緩存 | Redis + redis 庫 |
| Web 框架集成(如Flask) | flask-caching(封裝Redis/內(nèi)存) |
| 高性能本地緩存 | pylibmc(基于memcached) |
五、總結
Python 緩存入門的核心是:
- 優(yōu)先用內(nèi)置工具(
lru_cache)解決簡單場景; - 需過期時間用
cachetools; - 分布式場景用 Redis;
- 設計緩存時必須考慮「過期時間」「失效策略」「命中率」,避免緩存穿透/雪崩。
緩存是性能優(yōu)化的「第一選擇」,但不要過度設計——先通過性能測試找到瓶頸,再針對性加緩存,而非盲目為所有函數(shù)加緩存。
到此這篇關于Python中緩存入門實戰(zhàn)之核心概念與用法詳解的文章就介紹到這了,更多相關Python緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
python基礎教程之popen函數(shù)操作其它程序的輸入和輸出示例
popen函數(shù)允許一個程序將另一個程序作為新進程啟動,并可以傳遞數(shù)據(jù)給它或者通過它接收數(shù)據(jù),下面使用示例學習一下他的使用方法2014-02-02
Python正則表達式?r'(.*)?are?(.*?)?.*'的深入理解
日常的開發(fā)工作中經(jīng)常會有處理字符串的需求,簡單的字符串處理,我們使用python內(nèi)置的字符串處理函數(shù)就可以了,但是復雜的字符串匹配就需要借助正則表達式了,這篇文章主要給大家介紹了關于Python正則表達式?r‘(.*)?are?(.*?)?.*‘的相關資料,需要的朋友可以參考下2022-07-07
對比Python中__getattr__和 __getattribute__獲取屬性的用法
這篇文章主要介紹了對比Python中__getattr__和 __getattribute__獲取屬性的用法,注意二者間的區(qū)別,__getattr__只作用于不存在的屬性,需要的朋友可以參考下2016-06-06
matplotlib之Pyplot模塊繪制三維散點圖使用顏色表示數(shù)值大小
在撰寫論文時常常會用到matplotlib來繪制三維散點圖,下面這篇文章主要給大家介紹了關于matplotlib之Pyplot模塊繪制三維散點圖使用顏色表示數(shù)值大小的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2022-08-08
使用urllib庫的urlretrieve()方法下載網(wǎng)絡文件到本地的方法
今天小編就為大家分享一篇使用urllib庫的urlretrieve()方法下載網(wǎng)絡文件到本地的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-12-12
keras中模型訓練class_weight,sample_weight區(qū)別說明
這篇文章主要介紹了keras中模型訓練class_weight,sample_weight區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05

