data - LRU cache
๐ง What is caching
์บ์ฑ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ค๋๋ฐ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๊ฑฐ๋, ์คํํ๋๋ฐ ์ค๋ ๊ฑธ๋ฆฌ๋ ์ฐ์ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฏธ๋ฆฌ ๊ณ์ฐํ์ฌ ํ์ํ ๋ ์ต์ด๋ก ํ๋ฒ๋ง ๊ณ์ฐํ์ฌ ์ ์ฅํด๋๊ณ ์ฌ์ฌ์ฉํ๋ ๊ธฐ์ ์ ์๋ฏธํฉ๋๋ค.
ํ๋ก ํธ์ค๋์์๋ ํด๋ฆฌ์ด์ธํธ ์ปดํจํฐ์ ์บ์๋ฅผ ๋๊ณ , ์ด ์บ์์ ์ ์ ๋ฐฉ๋ฌธํ๋ ์นํ์ด์ง์ ๋ด์ฉ์ ์ ์ฅํด๋๊ณ ๋์ผํ ํ์ด์ง๋ฅผ ์ฌ๋ฐฉ๋ฌธ์ ์ด ์ ์ฅํด๋์ ์ฌ๋ณธ์ ํ์ด์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ฐฉ์์ ์ทจํ ์ ์์ต๋๋ค.
๋ฐฑ์๋์์๋ ํด๋ผ์ด์ธํธ์์ ๋ฐ์ ์์ฒญ์ ๋ํ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅํด๋๊ณ , ๋์ค์ ๋์ผํ ์์ฒญ์ด ๋ค์ด์์ ๋, ์ ์ฅํด๋ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋๋ก ์๋ตํฉ๋๋ค. ์ด๋ ๊ฒ ํ์ฌ ์กฐํ ์๋๋ฅผ ํฅ์์ํค๊ณ , ์๋ฒ ๋จ์ ๋ถํ๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.
๋คํธ์ํฌ์์๋ ํ๋ก์ ์๋ฒ๋ CDN์ ๋ํ์ ์ธ ์บ์ฑ ์ฌ๋ก๋ก ๋ณผ ์ ์์ต๋๋ค.
์บ์ฑ ์ ๋ต์ด๋?
์ผ๋ฐ์ ์ผ๋ก ์บ์ฑ์ ์ํด ์ฌ์ฉ๋๋ ์ ์ฅ ๋งค์ฒด๋ ๊ฐ๊ฒฉ์ด ๋น์๋๋ค. ๋ฐ๋ผ์, ์ ์ฅ ๋ฉ์ฒด์ ์ฉ๋์ ์ ํํ์ฌ ์ต๋ํ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๋ ์ ๋ต์ ์ทจํฉ๋๋ค. ์ด๊ฒ์ ์บ์ฑ ์ ๋ต์ด๋ผ๊ณ ํฉ๋๋ค.
์บ์ฑ ์ ๋ต์ ์บ์ ์ฉ๋์ด ๊ฝ ์ฐผ์ ๋, ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ๋จ๊ฒจ๋๊ณ , ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ์ง์์ผํ ์ง์ ๋ํ ๋ฐฉ๋ฒ์ ๋ปํฉ๋๋ค. ์บ์ฑ ์ ๋ต์๋ ์๋์ ๊ฐ์ ์ข ๋ฅ๊ฐ ์์ต๋๋ค.
LRU(Least Recently Used) cache
MRU(Most Recently Used) cache
LFU(Least Frequently Used) cache
์บ์ฑ ์ ๋ต - LRU cache(Least Recently Used)
์ฌ๊ธฐ์๋ LRU cache ์ ๋ต์ ๋ํด์ ์์๋ณด๊ณ ์ ํฉ๋๋ค.
LRU cache ์ ๋ต์ ์ต๊ทผ์ ์ฌ์ฉ๋ ๋ฐ์ดํฐ์ผ์๋ก ์์ผ๋ก๋ ์ฌ์ฉ๋ ๊ฐ๋ฅ์ฑ์ด ๋๋ค๋ผ๋ ๊ฐ์ค์ ๋ฐํ์ผ๋ก ๋ง๋ค์ด์ก์ต๋๋ค. ์ด ์ ๋ต์ ๊ฐ์ฅ ์ค๋ซ๋์ ์ฐธ์กฐ(์ฌ์ฉ)๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ์ฌ ๊ณต๊ฐ์ ํ๋ณดํ๊ณ , ์กฐํํ ๋ฐ์ดํฐ๋ ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉ๋ ๋ฐ์ดํฐ๋ก ๊ฐ์ฃผํฉ๋๋ค. ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ ํ๋์ด์๊ณ ์์ฃผ ์์ธ์คํ๋ ๋ฐ์ดํฐ์ ๋น ๋ฅด๊ฒ ์์ธ์ค ํ ์ ์์ด์ผ ํ๋ ์๋๋ฆฌ์ค์ ์ ์ฉํฉ๋๋ค.
LRU cache์ ์ธ๋ถ ๋์๋ฐฉ์์ ์๋์ ๊ฐ์ต๋๋ค.
์๋ก์ด ๋ฐ์ดํฐ๊ฐ ์ถ๊ฐ๋ ๊ฒฝ์ฐ,
์บ์์ ๊ณต๊ฐ์ด ๊ฐ๋์ฐจ์ง ์์ ๊ฒฝ์ฐ, ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฅ ์ต๊ทผ ์์น๋ก ์ด๋์ํต๋๋ค.
์บ์์ ๊ณต๊ฐ์ด ๊ฐ๋์ฐฌ ๊ฒฝ์ฐ, ๊ฐ์ฅ ์ค๋ซ๋์ ์ฌ์ฉ๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ๊ณ , ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฅ ์ต๊ทผ ์์น๋ก ์ด๋์ํต๋๋ค.
์ด๋ฏธ ์กด์ฌํ๋ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๊ฒฝ์ฐ,
ํด๋น ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฅ ์ต๊ทผ ์์น๋ก ์ด๋์ํต๋๋ค.
๐ ์ฉ์ด๋ ์์๋๋ฉด ์ข์ต๋๋ค.
Cache Hit: ์บ์์ ์ํ๋ ๋ฐ์ดํฐ๊ฐ ์์ด, ๋์คํฌ์ ์ ๊ทผํ์ง ์๊ณ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ
Cache Miss: ์บ์์ ์ํ๋ ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฒ
Eviction: ์บ์ ๊ณต๊ฐ์ด ๊ฝ์ฐจ์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ๋ ๊ฒ
LRU cache ๋์๋ฐฉ์ ์์๋ณด๊ธฐ
์๋์ ์์์์๋ ๊ฐ์ฅ ์ผ์ชฝ์ ์๋ ๋ฐ์ดํฐ๊ฐ ๊ฐ์ฅ ์ต์ ์ [์กฐํ/์ฝ์ ] ๋ฐ์ดํฐ๋ผ๊ณ ๊ฐ์ ํฉ๋๋ค.
# ์บ์ ํฌ๊ธฐ๊ฐ 3์ธ ์ด๊ธฐ ์ํ
[empty, empty, empty]
# ๋ฐ์ดํฐ 1 ์ ๊ทผ, ๋ฐ์ดํฐ๊ฐ ์๊ธฐ ๋๋ฌธ์ 1์ถ๊ฐ
[1, empty, empty]
# ๋ฐ์ดํฐ 2 ์ ๊ทผ, ๋ฐ์ดํฐ๊ฐ ์๊ธฐ ๋๋ฌธ์ 2์ถ๊ฐ, 2 ๊ฐ์ฅ ์ฒ์์ผ๋ก
[2, 1, empty]
# ๋ฐ์ดํฐ 3 ์ ๊ทผ, ๋ฐ์ดํฐ๊ฐ ์๊ธฐ ๋๋ฌธ์ 3์ถ๊ฐ, 3 ๊ฐ์ฅ ์ฒ์์ผ๋ก
[3, 2, 1]
# ๋ฐ์ดํฐ 4 ์ ๊ทผ, 4 ๋ฐ์ดํฐ ์๊ธฐ ๋๋ฌธ์ 4์ถ๊ฐ, 4 ๊ฐ์ฅ ์ฒ์์ผ๋ก, ๊ฐ์ฅ ๋ง์ง๋ง ์์(1) ์ ๊ฑฐ
[4, 3, 2]
# ๋ฐ์ดํฐ 2 ์ ๊ทผ, ๋ฐ์ดํฐ๊ฐ ์๊ณ , 2 ๊ฐ์ฅ ์ฒ์์ผ๋ก
[2, 4, 3]
# ๋ฐ์ดํฐ 4 ์ ๊ทผ, ๋ฐ์ดํฐ๊ฐ ์๊ณ , 4 ๊ฐ์ฅ ์ฒ์์ผ๋ก
[4, 2, 3] # 4๊ฐ ๊ฐ์ฅ ์ต๊ทผ ์ฌ์ฉ๋ ๋ฐ์ดํฐ๊ฐ ๋จPython์์ LRU ์บ์ ์ฌ์ฉ
functools ๋ชจ๋์ lru_cache ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ LRU ์บ์๋ฅผ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
import random
from functools import lru_cache
def fetch_num(n: int):
print(f'Fetching num: {n}')
return n
@lru_cache(maxsize=3)
def get_num(n: int) -> int:
return fetch_num(n)
def main():
for _ in range(10):
get_num(random.randint(0, 10))
print(get_num.cache_info())
if __name__ == '__main__':
main()
# Fetching num: 1
# Fetching num: 7
# Fetching num: 2
# Fetching num: 0
# Fetching num: 9
# Fetching num: 5
# CacheInfo(hits=4, misses=6, maxsize=3, currsize=3) << ๋๋ค์ผ๋ก ๋ณ๊ฒฝ๋จmaxsize ์ ์๋ฏธ
lru_cache ๋ฐ์ฝ๋ ์ด์ ๋งค๊ฐ๋ณ์ maxsize๋ ์บ์์ ์ ์ฅํ ์ ์๋ ์ต๋ ํญ๋ชฉ ์๋ฅผ ์ง์ ํฉ๋๋ค. ์บ์๊ฐ ์ด ํฌ๊ธฐ๋ฅผ ์ด๊ณผํ๋ฉด ์ต๊ทผ์ ๊ฐ์ฅ ์ ๊ฒ ์ฌ์ฉ๋ ํญ๋ชฉ์ ์ ํญ๋ชฉ์ ์ํ ๊ณต๊ฐ์ ํ๋ณดํ๊ธฐ ์ํด ์ ๊ฑฐ๋ฉ๋๋ค.
๋ช ์์ ์ผ๋ก ์ง์ ํ์ง ์์ ๊ฒฝ์ฐ maxsize์ ๊ธฐ๋ณธ ๊ฐ์ 128์ ๋๋ค. ์ด ๊ฐ์ None์ผ๋ก ์ค์ ํ๋ฉด ์บ์๊ฐ ์ ํ ์์ด ์ปค์ง ์ ์๊ธฐ ๋๋ฌธ์ ์ฃผ์ํด์ผํฉ๋๋ค.
LRU ์บ์ ํด๋์ค ๊ตฌํ
from collections import OrderedDict
class LRUCache:
def __init__(self, max_size):
self.cache = OrderedDict()
self.max_size = max_size
def get(self, key):
if key in self.cache:
# ํค๋ฅผ ๊ฐ์ฅ ์ต๊ทผ ์ฌ์ฉ๋ ์ํ๋ก ๊ฐฑ์
value = self.cache.pop(key)
self.cache[key] = value
return value
return None
def put(self, key, value):
if key in self.cache:
# ๊ธฐ์กด ํค๋ฅผ ์ ๊ฑฐํ์ฌ ์ต๊ทผ ์ฌ์ฉ๋ ์ํ๋ก ๊ฐฑ์
self.cache.pop(key)
elif len(self.cache) >= self.max_size:
# ์บ์๊ฐ ๊ฐ๋ ์ฐฌ ๊ฒฝ์ฐ ๊ฐ์ฅ ์ค๋๋ ํญ๋ชฉ ์ ๊ฑฐ
self.cache.popitem(last=False)
# ์๋ก์ด ํค-๊ฐ ์ ์ถ๊ฐ
self.cache[key] = value
def __str__(self):
return str(self.cache)
max_size = 3 # ์ต๋ ํฌ๊ธฐ๋ฅผ 3์ผ๋ก ์ค์
lru_cache = LRUCache(max_size)
lru_cache.put("a", "apple")
lru_cache.put("b", "banana")
lru_cache.put("c", "cherry")
print(lru_cache) # ์ถ๋ ฅ: OrderedDict([('a', 'apple'), ('b', 'banana'), ('c', 'cherry')])
# ์ ๊ทผํ์ฌ 'a'๋ฅผ ์ต์ ์ํ๋ก ๊ฐฑ์
print(lru_cache.get("a")) # ์ถ๋ ฅ: apple
print(lru_cache) # ์ถ๋ ฅ: OrderedDict([('b', 'banana'), ('c', 'cherry'), ('a', 'apple')])
# ์๋ก์ด ํญ๋ชฉ ์ถ๊ฐ๋ก ์ธํด ๊ฐ์ฅ ์ค๋๋ 'b'๊ฐ ์ ๊ฑฐ๋จ
lru_cache.put("d", "durian")
print(lru_cache) # ์ถ๋ ฅ: OrderedDict([('c', 'cherry'), ('a', 'apple'), ('d', 'durian')])
# ์กด์ฌํ์ง ์๋ ํค ์ ๊ทผ ์ None ๋ฐํ
print(lru_cache.get("b")) # ์ถ๋ ฅ: None
print(lru_cache) # ์ถ๋ ฅ: OrderedDict([('c', 'cherry'), ('a', 'apple'), ('d', 'durian')])
max_size = 3 # ์ต๋ ํฌ๊ธฐ๋ฅผ 3์ผ๋ก ์ค์
lru_cache = LRUCache(max_size)
lru_cache.put("a", "apple")
lru_cache.put("b", "banana")
lru_cache.put("c", "cherry")
print(lru_cache) # ์ถ๋ ฅ: OrderedDict([('a', 'apple'), ('b', 'banana'), ('c', 'cherry')])
# ์ ๊ทผํ์ฌ 'a'๋ฅผ ์ต์ ์ํ๋ก ๊ฐฑ์
print(lru_cache.get("a")) # ์ถ๋ ฅ: apple
print(lru_cache) # ์ถ๋ ฅ: OrderedDict([('b', 'banana'), ('c', 'cherry'), ('a', 'apple')])
# ์๋ก์ด ํญ๋ชฉ ์ถ๊ฐ๋ก ์ธํด ๊ฐ์ฅ ์ค๋๋ 'b'๊ฐ ์ ๊ฑฐ๋จ
lru_cache.put("d", "durian")
print(lru_cache) # ์ถ๋ ฅ: OrderedDict([('c', 'cherry'), ('a', 'apple'), ('d', 'durian')])
# ์กด์ฌํ์ง ์๋ ํค ์ ๊ทผ ์ None ๋ฐํ
print(lru_cache.get("b")) # ์ถ๋ ฅ: None
print(lru_cache) # ์ถ๋ ฅ: OrderedDict([('c', 'cherry'), ('a', 'apple'), ('d', 'durian')])
# LRUCache ํด๋์ค
- __init__(self, max_size): ์ต๋ ์บ์ ํฌ๊ธฐ๋ฅผ ์ค์ ํ๋ ์์ฑ์์
๋๋ค.
- get(self, key): ํค๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ ๊ฐ์ ธ์ต๋๋ค. ํค๊ฐ ์กด์ฌํ๋ฉด ๊ฐ์ฅ ์ต๊ทผ ์ฌ์ฉ๋ ์ํ๋ก ๊ฐฑ์ ํฉ๋๋ค.
- put(self, key, value): ํค-๊ฐ ์์ ์บ์์ ์ถ๊ฐํฉ๋๋ค. ์บ์๊ฐ ๊ฐ๋ ์ฐจ๋ฉด ๊ฐ์ฅ ์ค๋๋ ํญ๋ชฉ์ ์ ๊ฑฐํฉ๋๋ค.
- __str__(self): ์บ์์ ํ์ฌ ์ํ๋ฅผ ๋ฌธ์์ด๋ก ๋ฐํํฉ๋๋ค.
- put ๋ฉ์๋๋ฅผ ํตํด ์บ์์ ๋ฌธ์์ด ๊ฐ์ ์ ์ฅํฉ๋๋ค.
- get ๋ฉ์๋๋ฅผ ํตํด ์บ์์์ ๊ฐ์ ๊ฐ์ ธ์ค๊ณ , ์ต๊ทผ ์ฌ์ฉ๋ ์ํ๋ก ๊ฐฑ์ ํฉ๋๋ค.
- ์บ์๊ฐ ๊ฐ๋ ์ฐฌ ์ํ์์ ์๋ก์ด ๊ฐ์ ์ถ๊ฐํ๋ฉด ๊ฐ์ฅ ์ค๋๋ ํญ๋ชฉ์ด ์ ๊ฑฐ๋ฉ๋๋ค.Last updated