Python Cookbook-6.11 緩存環的實現

任務

你想定義一個固定尺寸的緩存,當它被填滿時,新加入的元素會覆蓋第一個(最老的)元素。這種數據結構在存儲日志和歷史信息時非常有用。

解決方案

當緩存填滿時,本節解決方案及時地修改了緩存對象,使其從未填滿的緩存類變成了填滿的緩存類:

class RingBuffer(object):"""這是一個未填滿的緩存類""" def __init__(self,size_max):self.max = size_maxself.data = [ ]class __Full(object):"""這是一個填滿了的緩存類""" def append(self,x):"""加入新的元素覆蓋最舊的元素"""self.data[self.cur] = xself.cur = (self.cur+1) % self.maxdef tolist(self):"""以正確的順序返回元素列表"""return self,data[self.cur:] + self.data[:self.cur]def append(self,x):"""在緩存末尾增加一個元素"""self.data.append(x)if len(self.data) == self.max:self.cur = 0#永久性地將self的類從非滿改成滿self.__class__ = self.__Fulldef tolist(self):"""返回一個從最舊的到最新的元素的列表"""return self.data
#用法示例
if __name__ == '__main__'x = RingBuffer(5)x.append(1);x.append(2);x.append(3);x.append(4)print x.__class__, x.tolist()x.append(5)print x.__class__, x.tolist()x.append(6)print x.data,x.tolist()x.append(7); x.append(8); x.append(9); x.append(10)print x.data,x.tolist()

討論

緩存環是有固定大小的緩存。當它被填滿時,加入新元素會覆蓋掉它持有的最舊的元素。在存儲日志和歷史信息時緩存環是非常有用數據結構。Python并沒有為這種數據結構提供直接支持,但用它構建一個這種結構卻輕而易舉。本節解決方案專門為元素插入進行了優化。

一個值得注意的設計要點是,這些對象在它們的生命周期中會經歷某種不可逆轉的狀態轉變——從未填滿的緩存變成填滿的緩存(從此時開始它的行為方式也發生了變化),我通過修改 self.__class__ 來完成這個轉變。這種方式對經典類和新風格類都同樣有效,只要這些舊的或者新的類的對象都擁有相同的槽(但對兩個沒有槽的新風格類也有效,比如本節的RingBufer和Full類)。注意,和其他語言不同,雖然Full類的實現位于 RingBufer 類的內部,但兩者并沒有什么特別的聯系,這樣其實很好,因為我們完全不需要這種聯系。

修改類實例在很多語言中會顯得很古怪,但在Python中,相比于其他一些隨意的、無法逆轉的、零散的修改方式,它是一種很好的選擇。而且,這樣的修改對于所有的類都是可行的。
緩存環(或者叫做有界的隊列)是一個很棒的點子,但是總測試緩存環有沒有被填滿是很低效的操作,我們也可以找到別的辦法,但是測試本身就是一件很討厭的事情。這種討厭的事情在 Python 世界中是不受歡迎的,雖然用Python 來做這些事并沒有什么難度,而且測試還涉及了更多的內存使用。關鍵就在于當環被填滿時,給__class__賦值以改變其行為方式,這也是它效率出眾的原因:這種類轉換是一次性的操作,所以它不會帶來任何性能上的開銷。

另一種選擇是,我們可以切換實例的兩個方法而非整個類,來使它變成填滿的狀態:

class RingBuffer(object):def __init__(self,size_max):self.max = size_maxself.data=[]def _full_append(self,x):self.data[self.cur] = xself.cur = (self.cur+1) % self.maxdef _full_get(self):return self.data[self.cur:] + self.data[:self.cur]def append(self,x):self.data.append(x)if len(self.data) == self.max:self.cur = 0#Permanently change self's methods from non-full to fullself.appand = self._full_appendself.tolist = self._full_getdef tolist(self):return self.data

這種切換的方式本質上等價于解決方案給出的類切換方式,盡管具體機制不同。當需要成組地切換所有的方法時,類切換的方式可能是最佳的,而方法切換則在需要更細的行為粒度控制的時候更加合適。當需要在新風格類中切換某些特殊方法時,類切換是唯一的辦法,這是因為它固有的特殊方法查詢是針對類進行的,而不是針對實例的(經典類和新風格類在這個方面截然不同)。

還可以使用其他很多方法來實現緩存環。在Python2.4中,可以考慮從新類型collections.deque 派生一個子類,這個類型提供了“雙頭隊列”,因而從任意一頭添加或者刪除數據的效率都是相當的:

from collections import deque
class RingBuffer(deque):def __init__(self,size_max):deque.__init__(self)self.size_max = size_maxdef append(self,datum):deque.append(self,datum)if len(self) > self.size_max:self.popleft()def tolist(self):return list(self)

或者,當環處于穩定狀態時,為了避免if語句,還可以混用方法切換:

from collections import deque
class RingBuffer(deque):def __init__(self,size_max):deque.__init__(self)self.size_max = size_maxdef _full_append(self,datum):deque.append(self,datum)self.popleft()def append(self,datum):deque.append(self,datum)if len(self) == self.size_max:self.append = self._full_appenddef tolist(self):return list(self)

在最后的這個實現中,我們只需要切換 append 方法(而tolist方法則保持原狀),在這里方法切換顯得比類切換更方便。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903113.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903113.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903113.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OpenCv高階(九)——背景建模

目錄 一、背景建模的核心目標與核心挑戰 1. 核心目標 2. 核心挑戰 ?二、背景建模模型 1、幀差法原理 2. 概率模型(Parametric Models) (1)高斯混合模型(Gaussian Mixture Model, GMM) (…

小重構,大收益!技術重構實踐:如何優雅升級老舊接口

重構格言:"優秀系統不是設計出來的,而是通過持續重構演進而來的。" —— Martin Fowler《重構:改善既有代碼的設計》 希望本文能為您的重構之旅提供指引,讓老舊系統煥發新生! 一、背景:一個“穩定…

OSPF中DR/BDR的選舉

OSPF 開放式最短路徑優先協議-CSDN博客 選舉原因:廣播網絡中使路由信息交換更加高速有序,可以降低需要維護的鄰接關系數量 基本概念: DR (Designated Router, 指定路由器):負責在廣播網絡(以太網)或NBMA網…

[特殊字符]?[特殊字符]Linux驅動開發入門 | 并發與互斥機制詳解

文章目錄 👨?💻Linux驅動開發入門 | 并發與互斥機制詳解📌為什么驅動中需要并發和互斥控制?💡常見的并發控制機制🔐自旋鎖和信號量通俗理解🌀自旋鎖(Spinlock)——“廁所…

Kafka 架構設計和組件介紹

什么是Apache Kafka? Apache Kafka 是一個強大的開源分布式事件流平臺。它最初由 LinkedIn 開發,最初是一個消息隊列,后來發展成為處理各種場景數據流的工具。 Kafka 的分布式系統架構支持水平擴展,使消費者能夠按照自己的節奏檢…

elk中kibana一直處于可用和降級之間且es群集狀態并沒有問題的解決方法

前言 在公司部elk的時候發現kibana的web界面一直很卡,數據量為0也會很卡,es群集狀態正常,資源足夠。 報錯信息 [2025-03-17T09:54:50.19400:00][INFO ][status] Kibana is now available (was degraded) [2025-03-17T09:55:03.28000:00][I…

什么是視頻上墻

視頻聯動上墻是指當監控系統中出現報警或其他特定事件時,相關的視頻畫面能夠自動切換并顯示在指定的監控大屏或顯示設備上,以便監控人員能夠快速、直觀地查看事件現場的情況,及時做出響應和處理。 具體介紹? 系統組成 :一般由前端…

26考研——存儲系統(3)

408答疑 文章目錄 一、存儲器概述二、主存儲器三、主存儲器與 CPU 的連接四、外部存儲器五、高速緩沖存儲器六、虛擬存儲器七、參考資料鮑魚科技課件26王道考研書 八、總結復習提示思考題常見問題和易混淆知識點 一、存儲器概述 文章鏈接: 點擊跳轉 二、主存儲器 文章鏈接: …

.NET 6 + Dapper + User-Defined Table Type

大家都知道,對于SQL Server IN是有限制條件的,如果IN里面的內容過多,在執行的時候會被自動截斷,因而導致查詢到的結果不是實際需要的結果。 select * from Payments where Id in (1,2,3,4,...) 為了解決上面的限制,可以…

MySQL 8(Ubuntu 18.04.6 LTS)安裝筆記

一、前言 其實之前已經寫過一篇筆記【MySQL 8.0.34(x64)安裝筆記】。機緣巧合,這次遇到的環境是Ubuntu 18.04 LTS,相比Windows平臺的安裝,對mysql的版本以及依賴的選擇,稍微要窄一些。特作筆記。 二、準備…

學習 Apache Kafka

學習 Apache Kafka 是一個很好的選擇,尤其是在實時數據流處理和大數據領域。以下是一個系統化的學習建議,幫助你從入門到進階掌握 Kafka: 1. 先決條件 在開始 Kafka 之前,確保你具備以下基礎: Java 基礎:K…

使用 binlog2sql 閃回 MySQL8 數據

【說明】 MySQL服務器版本 8.0.26 mysql> SELECT version(); ----------- | version() | ----------- | 8.0.26 | -----------Python 版本 Python 3.8.10 [infuq ~]# python -V Python 3.8.10【安裝】 binlog2sql 官方地址 1.安裝 binlog2sql [infuq ~]# git clone …

JavaScript 異步編程與請求取消全指南

JavaScript 異步編程與請求取消全指南 涵蓋:同步/異步、Promise、async/await、AbortController、前后端協作 一、同步與異步 1. 同步(Synchronous) 定義:代碼按順序執行,前一步完成才能執行下一步。特點&#xff1…

永久緩存 Git 憑證

永久緩存 Git 憑證 打開終端或命令行工具。 執行以下命令,設置 Git 使用 store 憑證幫助程序: bash git config --global credential.helper store第一次執行 git pull 時輸入賬號密碼。之后,所有需要憑證的操作都將自動使用存儲的憑證&…

力扣-48.旋轉圖像

題目描述 給定一個 n n 的二維矩陣 matrix 表示一個圖像。請你將圖像順時針旋轉 90 度。 你必須在 原地 旋轉圖像&#xff0c;這意味著你需要直接修改輸入的二維矩陣。請不要 使用另一個矩陣來旋轉圖像。 class Solution { public:void rotate(vector<vector<int>…

Qt ModbusSlave多線程實踐總結

最近項目中用到了ModbusSlave&#xff0c;也就是Modbus從設備的功能&#xff0c;之前用的基本都是master設備&#xff0c;所以讀取數據啥的用單線程就行了&#xff0c;用 void WaitHelper::WaitImplByEventloop(int msec) {QEventLoop loop;QTimer::singleShot(msec, &loop…

opencv--圖像

像素(像素點) 定義&#xff1a; Pixel 是 Picture Element&#xff08;圖像元素&#xff09;的縮寫&#xff0c;是數字圖像中最小的獨立單位。每個像素代表圖像中的一個點的顏色和亮度信息。 關鍵特性&#xff1a; 顏色&#xff1a;通過不同的色彩模型&#xff08;如RGB、CMYK…

記錄學習匯編語言02+各種寄存器分類

8086cpu是十六位的 然后寄存器能存八位 所以分為高八位低八位 高八位在下面低八位在上面 從下往上讀&#xff08;從地址小的地方開始讀&#xff09; 8086cpu種有兩個和棧相關的寄存器 棧段寄存器ss&#xff08;棧頂的段寄存器&#xff09; 棧頂指針寄存器sp&#xff08;…

OpenCV 圖形API(53)顏色空間轉換-----將 RGB 圖像轉換為灰度圖像函數RGB2Gray()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 將圖像從 RGB 色彩空間轉換為灰度。 R、G 和 B 通道值的常規范圍是 0 到 255。生成的灰度值計算方式如下&#xff1a; dst ( I ) 0.299 ? src…

(51單片機)LCD顯示數據存儲(DS1302時鐘模塊教學)(LCD1602教程)(獨立按鍵教程)(延時函數教程)(I2C總線認識)(AT24C02認識)

目錄 演示視頻&#xff1a; 源代碼 main.c LCD1602.c LCD1602.h AT24C02.c AT24C02.h Key.c Key.h I2C.c I2C.h Delay.c Delay.h 代碼解析與教程&#xff1a; Dealy模塊 LCD1602模塊 Key模塊 I2C總線模塊 AT24C02模塊 /E2PROM模塊 main模塊 演示視頻&#xff1a; E2…