快取旁路模式是一種常見的快取策略,旨在提升系統讀取效能。其實作原理是先檢查快取是否存在所需資料,若存在則直接傳回;若不存在,則從資料函式庫讀取資料,並將其存入快取,以供下次快速存取。本文以名言資料函式庫為例,使用 Redis 作為快取系統,SQLite 作為資料函式庫,並以 Python 程式碼示範如何實作快取旁路模式。程式碼中包含了資料函式庫初始化、名言新增、快取讀取等功能,並透過使用者互動介面進行操作。此外,文章也介紹了記憶化模式,一種透過快取函式運算結果來避免重複計算的技術。以費波那契數列計算為例,展示了記憶化模式如何顯著提升程式效能,並提供 Python 程式碼實作範例,說明如何使用 @lru_cache 裝飾器實作記憶化。最後,文章也簡述了延遲載入模式,一種僅在需要時才載入資源的技術,並說明其應用場景和優點。
快取旁路模式的實作與應用
快取旁路(Cache-Aside)模式是一種常見的快取策略,主要用於提升系統的讀取效能。在本篇文章中,我們將探討快取旁路模式的基本原理,並透過一個實際的範例來展示其實作方法。
快取旁路模式的基本原理
快取旁路模式的核心思想是,當應用程式需要讀取資料時,首先檢查快取中是否存在該資料。如果存在,則直接從快取中讀取;如果不存在,則從資料函式庫中讀取,並將資料存入快取中,以便下次快速讀取。
案例1:讀取資料專案
- 檢查快取中是否存在該資料。
- 如果存在,則直接從快取中讀取。
- 如果不存在,則從資料函式庫中讀取,並將資料存入快取中。
案例2:更新資料專案
- 將資料寫入資料函式庫。
- 從快取中刪除對應的資料專案。
實作範例:名言資料函式庫與快取系統
在這個範例中,我們將建立一個名言資料函式庫,並使用 Redis 作為快取系統。我們將實作一個簡單的應用程式,用於新增名言到資料函式庫和快取中,以及根據名言 ID 讀取名言。
環境設定與依賴套件
- SQLite 資料函式庫:用於儲存名言資料。
- Redis 伺服器與 redis-py Python 模組:用於實作快取系統。
- Faker 模組:用於產生虛擬的名言資料。
資料函式庫設定與名言新增功能
import sqlite3
from pathlib import Path
from random import randint
import redis
from faker import Faker
fake = Faker()
DB_PATH = Path(__file__).parent / Path("quotes.sqlite3")
cache = redis.StrictRedis(host="localhost", port=6379, decode_responses=True)
def setup_db():
try:
with sqlite3.connect(DB_PATH) as db:
cursor = db.cursor()
cursor.execute("""
CREATE TABLE quotes(id INTEGER PRIMARY KEY, text TEXT)
""")
db.commit()
print("Table 'quotes' created")
except Exception as e:
print(e)
def add_quotes(quotes_list):
added = []
try:
with sqlite3.connect(DB_PATH) as db:
cursor = db.cursor()
for quote_text in quotes_list:
quote_id = randint(1, 100)
quote = (quote_id, quote_text)
cursor.execute("""
INSERT OR IGNORE INTO quotes(id, text) VALUES(?, ?)
""", quote)
added.append(quote)
db.commit()
except Exception as e:
print(e)
return added
快取旁路模式的實作
import sqlite3
from pathlib import Path
import redis
CACHE_KEY_PREFIX = "quote"
DB_PATH = Path(__file__).parent / Path("quotes.sqlite3")
cache = redis.StrictRedis(host="localhost", port=6379, decode_responses=True)
def get_quote(quote_id: str) -> str:
out = []
quote = cache.get(f"{CACHE_KEY_PREFIX}.{quote_id}")
if quote is None:
query_fmt = "SELECT text FROM quotes WHERE id = {}"
try:
with sqlite3.connect(DB_PATH) as db:
cursor = db.cursor()
res = cursor.execute(query_fmt.format(quote_id)).fetchone()
if not res:
return "There was no quote stored matching that id!"
quote = res[0]
out.append(f"Got '{quote}' FROM DB")
except Exception as e:
print(e)
quote = ""
if quote:
key = f"{CACHE_KEY_PREFIX}.{quote_id}"
cache.set(key, quote, ex=60)
out.append(f"Added TO CACHE, with key '{key}'")
else:
out.append(f"Got '{quote}' FROM CACHE")
if out:
return " - ".join(out)
else:
return ""
程式碼解析
get_quote函式:根據名言 ID 讀取名言。如果快取中不存在,則從資料函式庫中讀取,並將結果存入快取。- 快取引擎:使用 Redis 作為快取系統,儲存名言資料。
- 資料函式庫操作:使用 SQLite 資料函式庫儲存名言資料,並在需要時查詢。
使用者互動介面
def main():
while True:
quote_id = input("Enter the ID of the quote: ")
# ... (省略其他程式碼)
圖表翻譯:
此圖示展示了快取旁路模式的基本流程:
graph LR
A[開始] --> B{檢查快取}
B -->|存在| C[從快取讀取]
B -->|不存在| D[從資料函式庫讀取]
D --> E[將資料存入快取]
C --> F[傳回結果]
E --> F
圖表翻譯: 此圖示呈現了快取旁路模式的運作流程,首先檢查快取是否存在所需資料,若存在則直接從快取讀取,若不存在則從資料函式庫讀取並存入快取,最後傳回結果。整個流程有效地減少了對資料函式庫的直接查詢,提升了系統的整體效能。
快取策略模式(Cache-Aside Pattern)實作與解析
快取策略模式是一種常見的效能最佳化技術,廣泛應用於軟體開發領域。本章節將探討快取策略模式的實作細節,並分析其在實際應用中的運作方式。
程式碼實作與測試
以下為測試快取策略模式的 Python 程式碼範例:
if quote_id.isdigit():
out = get_quote(quote_id)
print(out)
else:
print("You must enter a number. Please retry.")
內容解密:
- 檢查
quote_id是否為數字。 - 若為數字,則呼叫
get_quote(quote_id)函式取得對應的。 - 若非數字,則輸出錯誤訊息,要求重新輸入。
快取策略模式的運作流程
- 首先,執行
python ch08/cache_aside/populate_db.py初始化資料函式庫。 - 選擇 “init” 模式,建立
quotes.sqlite3資料函式庫檔案及quotes表格。 - 執行
python ch08/cache_aside/populate_db.py並選擇 “update_all” 模式,更新資料函式庫並將新資料加入快取。
輸出範例:
New (fake) quotes added to the database:
Added to DB: (62, 'Instead not here public.')
- Also adding to the cache
Added to DB: (26, 'Training degree crime serious beyond management and.')
- Also adding to the cache
內容解密:
populate_db.py程式碼負責初始化及更新資料函式庫內容。- 當選擇 “update_all” 模式時,新的會被加入資料函式庫並同步更新至快取中。
快取策略模式的測試結果
執行 python ch08/cache_aside/cache_aside.py 並輸入不同的 ID,觀察其輸出結果:
Enter the ID of the quote: 23
Got 'Dark team exactly really wind.' FROM DB - Added TO CACHE, with key 'quote.23'
Enter the ID of the quote: 12
There was no quote stored matching that id!
內容解密:
- 當輸入存在的 ID(如 23),系統會從資料函式庫中取出資料並加入快取。
- 當輸入不存在的 ID(如 12),系統會回報查無資料。
Memoization 模式簡介
Memoization 是一種重要的效能最佳化技術,透過快取函式的計算結果,避免重複運算。
實際應用範例
- 費氏數列計算:透過儲存已計算的值,避免重複運算。
- 文字搜尋演算法:快取搜尋結果,加速相同查詢的處理速度。
Memoization 模式的實作
以下為使用 Python 的 functools.lru_cache 裝飾器實作 Memoization 的範例:
from datetime import timedelta
from functools import lru_cache
def fibonacci_func1(n):
if n < 2:
return n
return fibonacci_func1(n-1) + fibonacci_func1(n-2)
@lru_cache(maxsize=None)
def fibonacci_func2(n):
if n < 2:
return n
return fibonacci_func2(n-1) + fibonacci_func2(n-2)
內容解密:
fibonacci_func1為未使用快取的遞迴實作,效能較差。fibonacci_func2使用@lru_cache裝飾器進行 Memoization,最佳化遞迴運算效能。maxsize=None表示無限制快取大小。
Memoization 模式的適用場景
- 最佳化遞迴演算法:降低時間複雜度。
- 減少運算負擔:避免不必要的重複計算。
- 提升應用效能:改善使用者經驗。
本章節介紹了快取策略模式及 Memoization 模式的實作與應用,讀者可根據實際需求選擇適合的最佳化技術。
效能模式實務應用:記憶化與延遲載入
在軟體開發領域中,效能最佳化一直是開發者關注的重點。其中,記憶化(Memoization)與延遲載入(Lazy Loading)是兩種常見且有效的效能最佳化模式。本文將探討這兩種模式的原理、實務應用及其程式碼實作。
記憶化模式詳解
記憶化是一種透過快取函式呼叫結果來避免重複計算的技術。以下以計算費波那契數列為例,展示記憶化的強大效能提升。
傳統遞迴實作 vs. 記憶化實作
首先,我們來看傳統的費波那契數列遞迴實作:
def fibonacci_func1(n):
if n < 2:
return n
return fibonacci_func1(n - 1) + fibonacci_func1(n - 2)
這種實作方式存在嚴重的效能問題,因為它會進行大量重複計算。
接下來,我們使用@lru_cache裝飾器來實作記憶化版本:
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci_func2(n):
if n < 2:
return n
return fibonacci_func2(n - 1) + fibonacci_func2(n - 2)
效能比較測試
我們編寫一個main()函式來測試這兩個函式的效能:
import time
from datetime import timedelta
def main():
n = 30
start_time = time.time()
result = fibonacci_func1(n)
duration = timedelta(seconds=time.time() - start_time)
print(f"Fibonacci_func1({n}) = {result}, calculated in {duration}")
start_time = time.time()
result = fibonacci_func2(n)
duration = timedelta(seconds=time.time() - start_time)
print(f"Fibonacci_func2({n}) = {result}, calculated in {duration}")
if __name__ == "__main__":
main()
執行結果顯示,fibonacci_func2(使用記憶化)的計算時間遠遠少於fibonacci_func1(傳統遞迴)。
程式碼解析
- 記憶化實作關鍵:使用
@lru_cache(maxsize=None)裝飾器對fibonacci_func2進行記憶化處理。 - 效能提升原因:避免了重複計算,將已計算的結果儲存在快取中,直接傳回快取結果而非重新計算。
- 適用場景:任何存在重複計算的場景,如動態規劃問題、遞迴演算法最佳化等。
延遲載入模式詳解
延遲載入是一種最佳化資源載入時間的技術,僅在需要時才載入資源。
實務應用場景
- 網頁圖片延遲載入:僅載入可視區域內的圖片。
- 影片串流服務:分段載入影片內容。
- 電子試算表軟體:僅載入目前檢視或操作相關的資料。
程式碼實作範例
以下是一個簡單的延遲載入實作範例:
class LazyLoadedData:
def __init__(self):
self._data = None
@property
def data(self):
if self._data is None:
self._data = self.load_data()
return self._data
def load_data(self):
print("Loading expensive data...")
# 模擬昂貴的操作,例如從資料函式庫讀取或複雜計算
return sum(i * i for i in range(100000))
def main():
obj = LazyLoadedData()
print("Object created, expensive attribute not loaded yet.")
print("Accessing expensive attribute:")
print(obj.data)
print("Accessing expensive attribute again:")
print(obj.data)
if __name__ == "__main__":
main()
程式碼解析
LazyLoadedData類別設計:透過@property裝飾器將data方法轉換為屬性,並在內部實作延遲載入邏輯。load_data方法:模擬一個耗時的資料載入或計算過程。- 首次存取觸發載入:當第一次存取
obj.data時,才會呼叫load_data方法進行資料載入。 - 再次存取直接傳回:第二次及之後的存取直接傳回已載入的資料,無需重複載入。