Skip to content

Instantly share code, notes, and snippets.

@Alfex4936
Created November 16, 2020 07:58
Show Gist options
  • Save Alfex4936/62ca4aaa19ccdea6fa98b8c69b472ec7 to your computer and use it in GitHub Desktop.
Save Alfex4936/62ca4aaa19ccdea6fa98b8c69b472ec7 to your computer and use it in GitHub Desktop.
LRU Cache implementation in Python
class Node:
__slots__ = ("key", "val", "prev", "next")
def __init__(self, key, val):
self.key = key
self.val = val
self.prev = None
self.next = None
from threading import Lock # Linked list updates aren't thread-safe
class LRU:
lock = Lock()
maxsize = None
__slots__ = ("function", "cache", "head", "tail", "hits", "miss")
def __init__(self, function):
self.function = function
self.cache = {}
self.head = Node("head", None)
self.tail = Node("tail", None)
self.head.next = self.tail
self.tail.prev = self.head
self.hits = 0
self.miss = 0
def __call__(self, *args, **kwargs):
if args in self.cache:
self._check()
self.hits += 1
self._get(args)
return self.cache[args]
self._check()
result = self.function(*args, **kwargs)
self.cache[args] = result
self.miss += 1
node = Node(args, result)
self._add(node)
return result
def cache_info(self):
return f"CacheInfo(hits={self.hits}, misses={self.miss}, maxsize={self.maxsize}, currsize={len(self.cache)})"
def _check(self):
if self.maxsize is not None and len(self.cache) >= self.maxsize:
node = self.head.next
self._remove(node)
if node.key in self.cache:
del self.cache[node.key]
def _add(self, node):
with self.lock:
p = self.tail.prev
p.next = node
self.tail.prev = node
node.prev = p
node.next = self.tail
def _remove(self, node):
with self.lock:
p = node.prev
n = node.next
p.next = n
n.prev = p
def _get(self, args):
head = self.head
tail = self.tail
while head and tail:
if head.key == args:
node = head
self._remove(node)
self._add(node)
break
head = head.next
if tail.key == args:
node = tail
self._remove(node)
self._add(node)
break
tail = tail.prev
def print(self):
head = self.head
while head != self.tail:
print(head.key, end=" -> ")
head = head.next
print("tail")
LRU.maxsize = 217
@LRU
def fibo(n):
if n == 1:
return 0
elif n == 2:
return 1
else:
return fibo(n - 1) + fibo(n - 2)
from timeit import default_timer
start = default_timer()
print(fibo(211))
print(f"{default_timer() - start:.5f}s")
print(fibo.cache_info())
fibo.print()
from functools import lru_cache
@lru_cache(maxsize=LRU.maxsize)
def fibo(n):
if n == 1:
return 0
elif n == 2:
return 1
else:
return fibo(n - 1) + fibo(n - 2)
start = default_timer()
print(fibo(211))
print(f"{default_timer() - start:.5f}s")
print(fibo.cache_info())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment