『码农翻身』高速缓存置换策略

计算机高速缓存

  • 字:是指存放在一个存储单元中的二进制代码的组合
  • 字块:存储在连续的存储单元中而被看作是一个单元的一组字

高速缓存由多个字块组成

高速缓存的替换策略

先进先出算法(FIFO)

  • 把高速缓存看作是一个先进先出的队列
  • 优先替换最先进入队列的字块

最不经常使用算法(LFU)

  • 优先淘汰最不经常使用的字块
  • 需要额外的空间记录字块的使用频率

最近最少使用算法(LRU)

  • 优先淘汰一段时间内没有使用的字块
  • 有多种实现方法,一般使用双向链表

页面置换算法的实现

双向链表

from typing import Any, Union


class Node(object):

    def __init__(self, key: Any, value: Any):
        self.key: Any = key
        self.value: Any = value
        self.prev: Node = None
        self.next: Node = None

    def __str__(self):
        val = f"{{{self.key}:{self.value}}}"
        return val

    def __repr__(self):
        val = f"{{{self.key}:{self.value}}}"
        return val


class LFUNode(Node):

    def __init__(self, key: Any, value: Any):
        super().__init__(key, value)
        self.freq: int = 0


class LinkedList(object):

    def __init__(self, capacity: int = 0xffff):
        self.capacity: int = capacity
        self.head: Union[Node, LFUNode] = None
        self.tail: Union[Node, LFUNode] = None
        self.size: int = 0

    # 从头部添加结点
    def __add_head(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode]:
        if not self.head:
            self.head = node
            self.tail = node
            self.head.prev = None
            self.tail.next = None
        else:
            node.next = self.head
            self.head.prev = node
            self.head = node
            self.head.prev = None

        self.size += 1

        return node

    # 从尾部添加结点
    def __add_tail(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode]:
        if not self.tail:
            self.tail = node
            self.head = node
            self.tail.next = None
            self.head.prev = None
        else:
            node.prev = self.tail
            self.tail.next = node
            self.tail = node
            self.tail.next = None

        self.size += 1

        return node

    def __del_tail(self) -> Union[Node, LFUNode, None]:
        if not self.tail:
            return

        node = self.tail
        if node.prev:
            self.tail = node.prev
            self.tail.next = None
        else:
            self.head = self.tail = None

        self.size -= 1

        return node

    def __del_head(self) -> Union[Node, LFUNode, Node]:
        if not self.head:
            return

        node = self.head

        if node.next:
            self.head = node.next
            self.head.prev = None
        else:
            self.head = self.tail = None

        self.size -= 1

        return node

    # 任意结点删除
    def __remove(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode, None]:
        if self.size <= 0:
            raise ValueError("链表为空!")
        if not node:
            node = self.tail

        if node == self.tail:
            self.__del_tail()
        elif node == self.head:
            self.__del_head()
        else:
            node.prev.next = node.next
            node.next.prev = node.prev
            self.size -= 1

        return node

    def pop(self) -> Union[Node, LFUNode, None]:
        return self.__del_head()

    def append(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode]:
        return self.__add_tail(node)

    def append_front(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode]:
        return self.__add_head(node)

    def remove(self, node: Union[Node, LFUNode] = None) -> Union[Node, LFUNode, None]:
        return self.__remove(node)

    def print(self):
        """调试用"""
        p = self.head
        line = ""
        while p:
            line += f"{p}"
            p = p.next
            if p:
                line += "=>"
        print(line)
        

FIFO 算法

from typing import Any, Union, Dict

from LinkedList import LinkedList, Node


class FIFOCache(object):

    def __init__(self, capacity: int):
        self.capacity: int = capacity
        self.size: int = 0
        self.map: Dict[Any, Node] = {}
        self.list: LinkedList[Node] = LinkedList(capacity)

    def get(self, key: Any) -> Union[int, Any]:
        if key not in self.map:
            return -1
        else:
            node = self.map[key]
            return node.value

    def put(self, key: Any, value: Any):
        if self.capacity == 0:
            return
        if key in self.map:
            node = self.map[key]
            self.list.remove(node)
            node.value = value
            self.list.append(node)
        else:
            if self.size == self.capacity:
                node = self.list.pop()
                del self.map[node.key]
                self.size -= 1
            node = Node(key, value)
            self.list.append(node)
            self.map[key] = node
            self.size += 1

    def print(self):
        """调试用"""
        self.list.print()
        

LFU 算法

from typing import Any, Dict, Union

from LinkedList import LFUNode, LinkedList


class LFUCache(object):

    def __init__(self, capacity: int):
        self.capacity: int = capacity
        self.map: Dict[Any, LFUNode] = {}
        self.freq_map: Dict[int, LinkedList] = {}  # key 是频率, value 是对应的双向链表
        self.size: int = 0

    def __update_freq(self, node: LFUNode):
        freq = node.freq

        node = self.freq_map[freq].remove(node)

        if self.freq_map[freq].size == 0:
            del self.freq_map[freq]

        freq += 1
        node.freq = freq

        if freq not in self.freq_map:
            self.freq_map[freq] = LinkedList()

        self.freq_map[freq].append(node)

    def get(self, key: Any) -> Union[int, Any]:
        if key not in self.map:
            return -1
        node = self.map[key]
        self.__update_freq(node)
        return node.value

    def put(self, key: Any, value: Any):
        if self.capacity == 0:
            return

        if key in self.map:
            node = self.map[key]
            node.value = value
            self.__update_freq(node)

        else:
            if self.capacity == self.size:
                min_freq = min(self.freq_map)
                node = self.freq_map[min_freq].pop()
                del self.map[node.key]
                self.size -= 1

            node = LFUNode(key, value)
            node.freq = 1
            self.map[key] = node
            if node.freq not in self.freq_map:
                self.freq_map[node.freq] = LinkedList()
            node = self.freq_map[node.freq].append(node)
            self.size += 1

    def print(self):
        print("****************************************")
        for k in self.freq_map:
            print(f"freq = {k}")
            self.freq_map[k].print()
        print("****************************************")
        print()
        

LRU 算法

from typing import Any, Union, Dict

from LinkedList import Node, LinkedList


class LRUCache(object):

    def __init__(self, capacity: int):
        self.map: Dict[Any, Node] = {}
        self.list: LinkedList[Node] = LinkedList(capacity)

    def get(self, key: Any) -> Union[int, Any]:
        if key in self.map:
            node = self.map[key]
            self.list.remove(node)
            self.list.append_front(node)
            return node.value
        else:
            return -1

    def put(self, key: Any, value: Any):
        if key in self.map:
            node = self.map[key]
            self.list.remove(node)
            node.value = value
            self.list.append_front(node)
        else:
            node = Node(key, value)
            # 如果链表缓存已满
            if self.list.size >= self.list.capacity:
                old_node = self.list.remove()
                self.map.pop(old_node.key)

            self.list.append_front(node)
            self.map[key] = node

    def print(self):
        self.list.print()
        
posted @ 2020-04-18 23:21  芜情  阅读(347)  评论(0编辑  收藏  举报