主頁 > 後端開發 > 聊一聊作為高并發系統基石之一的快取,會用很簡單,用好才是技識訓

聊一聊作為高并發系統基石之一的快取,會用很簡單,用好才是技識訓

2022-10-27 06:38:59 後端開發

大家好,又見面了,


本文是筆者作為掘金技術社區簽約作者的身份輸出的快取專欄系列內容,將會通過系列專題,講清楚快取的方方面面,如果感興趣,歡迎關注以獲取后續更新,


在服務端開發中,快取常常被當做系統性能扛壓的不二之選,在實施方案上,快取使用策略雖有一定普適性,卻也并非完全絕對,需要結合實際的專案訴求與場景進行綜合權衡與考量,進而得出符合自己專案的最佳實踐,

快取使用的演進

現有這么一個系統:

一個互動論壇系統,用戶登錄系統之后,可以在論壇上查看帖子串列、查看帖子詳情、發表帖子、評論帖子、為帖子點贊等操作,

系統中所有的配置資料與業務資料均存盤在資料庫中,隨著業務的發展,注冊用戶量越來越多,然后整個系統的回應速度也越來越慢,用戶體驗越來越差,用戶逐漸出現流失,

本地快取的牛刀小試

為了挽救這一局面,開發人員需要介入去分析性能瓶頸并嘗試優化提升回應速度,并很快找到回應慢的瓶頸在資料庫的頻繁操作,于是想到了使用快取來解決問題,

于是,開發人員在專案中使用了基于介面維度的短期快取,對每個介面的請求引數(帖子ID)與回應內容快取一定的時間(比如1分鐘),對于相同的請求,如果匹配到快取則直接回傳快取的結果即可,不用再次去執行查詢資料庫以及業務維度的運算邏輯,

JAVA中有很多的開源框架都有提供類似的能力支持,比如Ehcache或者Guava CacheCaffeine Cache等,可以通過簡單的添加注解的方式就實作上述需要的快取效果,比如使用Ehcache來實作介面介面快取的時候,代碼使用方式如下(這里先簡單的演示下,后續的系列檔案中會專門對這些框架進行深入的探討):

@Cacheable(value="https://www.cnblogs.com/softwarearch/archive/2022/10/26/UserDetailCache", key="#userId")
public UserDetail queryUserDetailById(String userId) {
    UserEntity userEntity = userMapper.queryByUserId(userId);
    return convertEntityToUserDetail(userEntity);
}

基上面的本地快取策略改動后重新上線,整體的回應性能上果然提升了很多,本地快取的策略雖然有效地提升了處理請求的速度,但新的問題也隨之浮現,有用戶反饋,社區內的帖子串列多次重繪后會出現內容不一致的情況,有的帖子重繪之后會從串列消失,多次重繪后偶爾會出現,

其實這就是本地快取在集群多節點場景下會遇到的一個很常見的快取漂移現象:

因為業務集群存在多個節點,而快取是每個業務節點本地獨立構建的,所以才出現了更新場景導致的本地快取不一致的問題,進而表現為上述問題現象,

集中式快取的初露鋒芒

為了解決集群內多個節點間執行寫操作之后,各節點本地快取不一致的問題,開發人員想到可以構建一個集中式快取,然后所有業務節點都讀取或者更新同一份快取資料,這樣就可以完美地解決節點間快取不一致的問題了,

業界成熟的集中式快取有很多,最出名的莫過于很多人都耳熟能詳的Redis,或者是在各種面試中常常被拿來與Redis進行比較的Memcached,也正是由于它們出色的自身性能表現,在當前的各種分布式系統中,Redis近乎已經成為了一種標配,常常與MySQL等持久化資料庫搭配使用,放在資料庫前面進行扛壓,比如下面圖中示例的一種最簡化版本的組網架構:

開發人員對快取進行了整改,將本地快取改為了Redis集中式快取,這樣一來:

  1. 快取不一致問題解決:解決了各個節點間資料不一致的問題,

  2. 單機記憶體容量限制解決:使用了Redis這種分布式的集中式快取,擴大了記憶體快取的容量范圍,可以順便將很多業務層面的資料全部加載到Redis中分片進行快取,性能也相比而言得到了提升,

似乎使用集中式快取已經是分布式系統中的最優解了,但是現實情況真的就這么簡單么?也不盡然

多級快取的珠聯璧合

在嘗到了集中式快取的甜頭之后,暖心的程式員們想到要徹底為資料庫減壓,將所有業務中需要頻繁使用的資料全部同步存盤到Redis中,然后業務使用的時候直接從Redis中獲取相關資料,大大地減少了資料庫的請求頻次,但是改完上線之后,發現有些處理流程中并沒有太大的性能提升,緣何如此?只因為對集中式快取的過分濫用!分析發現這些流程的處理需要涉及大量的互動與資料整合邏輯,一個流程需要訪問近乎30次Redis!雖然Redis的單次請求處理性能極高,甚至可以達到微秒級別的回應速度,但是每個流程里面幾十次的網路IO互動,導致頻繁的IO請求,以及執行緒的阻塞喚醒切換交替,使得系統在執行緒背景關系切換層面浪費巨大

那么,要想破局,最常規的手段便是嘗試降低對集中式快取(如Redis)的請求數量,降低網路IO互動次數,而如何來降低呢? —— 又回到了本地快取!集中式快取并非是分布式系統中提升性能的銀彈,但我們可以將本地快取與集中式快取結合起來使用,取長補短,實作效果最大化,如圖所示:

上圖演示的也即多級快取的策略,具體而言:

  • 對于一些變更頻率比較高的資料,采用集中式快取,這樣可以確保資料變更之后所有節點都可以實時感知到,確保資料一致;

  • 對于一些極少變更的資料(比如一些系統配置項)或者是一些對短期一致性要求不高的資料(比如用戶昵稱、簽名等)則采用本地快取,大大減少對遠端集中式快取的網路IO次數,

這樣一來,系統的回應性能又得到了進一步的提升,

通過對快取使用策略的一步步演進,我們可以感受到快取的恰當使用對系統性能的幫助作用,

無處不在的快取

快取存在的初衷,就是為了兼容兩個處理速度不一致的場景對接適配的,在我們的日常生活中,也常常可以看到“快取”的影子,比如對于幾年前比較盛行的那種帶桶的凈水器(見下圖),由于凈水的功率比較小,導致實時過濾得到純凈水的水流特別的緩慢,用戶倒一杯水要等2分鐘,體驗太差,所以配了個蓄水桶,凈水機先慢慢的將凈化后的水存盤到桶中,然后用戶倒水的時候可以從桶里快速的倒出,無需焦急等待 —— 這個蓄水桶,便是一個快取器

編碼源于生活,CPU高速快取設計就是這一生活實踐在計算機領域的原樣復制,快取可以說在軟體世界里無處不在,除了我們自己的業務系統外,在網路傳輸作業系統中間件基礎框架中都可以看到快取的影子,如:

  1. 網路傳輸場景

比如ARP協議,基于ARP快取表進行IP與終端硬體MAC地址之間的快取映射,這樣與對端主機之間有通信需求的時候,就可以在ARP快取中查找到IP對應的對端設備MAC地址,避免每次請求都需要去發送ARP請求查詢MAC地址,

  1. MyBatis的多級快取

MyBatis作為JAVA體系中被廣泛使用的資料庫操作框架,其內部為了提升處理效率,構建了一級快取二級快取,大大減少了對SQL的重復執行次數,

  1. CPU中的快取

CPU記憶體之間有個臨時存盤器(高速快取),容量雖比記憶體小,但是處理速度卻遠快于普通記憶體,高速快取的機制,有效地解決了CPU運算速度記憶體讀寫速度不匹配的問題,

快取的使用場景

快取作為互聯網類軟體系統架構與實作中的基石般的存在,不僅僅是在系統扛壓或者介面處理速度提升等性能優化方案,在其他多個方面都可以發揮其獨一無二的關鍵價值,下面就讓我們一起來看看快取都可以用在哪些場景上,可以解決我們哪方面的痛點,

降低自身CPU消耗

如前面章節中提到的專案實體,快取最典型的使用場景就是用在系統的性能優化上,而在性能優化層面,一個經典的策略就是“空間換時間”,比如:

  • 在資料庫表中做一些欄位冗備

比如用戶表T_User和部門表T_Department,在T_User表中除了有個Department_Id欄位與T_Department表進行關聯之外,還額外在T_User表中存盤Department_Name值,這樣在很多需要展示用戶所屬部門資訊的時候就省去了多表關聯查詢的操作,

  • 對一些中間處理結果進行存盤

比如系統中的資料報表模塊,需要對整個系統內所有的關聯業務資料進行計算統計,且需要多張表多來源資料之間的綜合匯總之后才能得到最終的結果,整個程序的計算非常的耗時,如果借助快取,則可以將一些中間計算結果進行暫存,然后報表請求中基于中間結果進行二次簡單處理即可,這樣可以大大降低基于請求觸發的實時計算量,

在“空間換時間”實施策略中,快取是該策略的核心、也是被使用的最為廣泛的一種方案,借助快取,可以將一些CPU耗時計算的處理結果進行快取復用,以降低重復計算作業量,達到降低CPU占用的效果,

減少對外IO互動

上面介紹的使用快取是為了不斷降低請求處理時對自身CPU占用,進而提升服務的處理性能,這里我們介紹快取的另一典型使用場景,就是減少系統對外依賴請求頻次,即通過將一些從遠端請求回來的回應結果進行快取,后面直接使用此快取結果而無需再次發起網路IO請求互動,

對于服務端而言,通過構建快取的方式來減少自身對外的IO請求,主要有幾個考量出發點:

  1. 自身性能層面考慮,減少對外IO操作,降低了對外介面的回應時延,也對服務端自身處理性能有一定提升,

  2. 對端服務穩定性層面考慮,避免對端服務負載過大,很多時候呼叫方和被呼叫方系統的承壓能力是不匹配的,甚至有些被呼叫方系統可能是不承壓的,為了避免將對端服務壓垮,需要呼叫方快取請求結果,降低IO請求,

  3. 自身可靠性層面而言,將一些遠端服務請求到的結果快取起來,即使遠端服務出現故障,自身業務依舊可以基于快取資料進行正常業務處理,起到一個兜底作用提升自身的抗風險能力

在分布式系統服務治理范疇內,服務注冊管理服務是必不可少的,比如SpringCloud家族的Eureka,或者是Alibaba開源的Nacos,它們對于快取的利用,可以說是對上面所提幾點的完美闡述,

Nacos為例:

除了上述的因素之外,對一些移動端APP或者H5界面而言,快取的使用還有一個層面的考慮,即降低用戶的流量消耗,通過將一些資源類資料快取到本地,避免反復去下載,給用戶省點流量,也可以提升用戶的使用體驗(界面渲染速度快,減少出現白屏等待的情況),

提升用戶個性化體驗

快取除了在系統性能提升或系統可靠性兜底等場景發揮價值外,在APP或者web類用戶側產品中,還經常被用于存盤一些臨時非永久的個性化使用習慣配置或者身份資料,以提升用戶的個性化使用體驗,

  • 快取cookiesession等身份鑒權資訊,這樣就可以避免用戶每次訪問都需要進行身份驗證,

  • 記住一些用戶上次操作習慣,比如用戶在一個頁面上將串列分頁查詢設定為100條/頁,則后續在系統內訪問其它串列頁面時,都沿用這一設定,

  • 快取用戶的一些本地設定,這個主要是APP端常用的功能,可以在快取中保存些與當前設備系結的設定資訊,僅對當前設備有效,比如同一個賬號登錄某個APP,用戶希望在手機端可以顯示深色主題,而PAD端則顯示淺色主體,這種基于設備的個性化設定,可以快取到設備本身即可,

業務與快取的集成模式

如前所述,我們可以在不同的方面使用快取來輔助達成專案在某些方面的訴求,而根據使用場景的不同,在結合快取進行業務邏輯實作的時候,也會存在不同的架構模式,典型的會有旁路型快取穿透型快取異步型快取三種,

旁路型快取

旁路型快取模式中,業務自行負責與快取以及資料庫之間的互動,可以自由決定快取未命中場景的處理策略,更加契合大部分業務場景的定制化訴求,

由于業務模塊自行實作快取與資料庫之間的資料寫入與更新的邏輯,實際實作的時候需要注意下在高并發場景的資料一致性問題,以及可能會出現的快取擊穿快取穿透快取雪崩等問題的防護,

旁路型快取是實際業務中最常使用的一種架構模式,在后面的內容中,我們還會不斷的涉及到旁路快取中相關的內容,

穿透型快取

穿透型快取在實際業務中使用的較少,主要是應用在一些快取類的中間件中,或者在一些大型系統中專門的資料管理模塊中使用,

一般情況下,業務使用快取的時候,會是先嘗試讀取快取,在嘗試讀取DB,而使用穿透型快取架構時,會有專門模塊將這些動作封裝成黑盒的,業務模塊不會與資料庫進行直接互動,如下圖所示:

這種模式對業務而言是比較友好的,業務只需呼叫快取介面即可,無需自行實作快取與DB之間的互動策略,

異步型快取

還有一種快取的使用模式,可以看作是穿透型快取的演進異化版本,其使用場景也相對較少,即異步型快取,其主要策略就是業務側請求的實時讀寫互動都是基于快取進行,任何資料的讀寫也完全基于快取進行操作,此外,單獨實作一個資料持久化操作(獨立執行緒或者行程中執行),用于將快取中變更的資料寫入到資料庫中,

這種情況,實時業務讀寫請求完全基于快取進行,而將資料庫僅僅作為一個資料持久化存盤的備份盤,由于實時業務請求僅與快取進行互動,所以在性能上可以得到更好的表現,但是這種模式也存在一個致命的問題:資料可靠性!因為是異步操作,所以在下一次資料寫入DB前,會有一段時間資料僅存在于快取中,一旦快取服務宕機,這部分資料將會丟失,所以這種模式僅適用于對資料一致性要求不是特別高的場景,

快取的優秀實踐

快取持久化存盤的一個很大的不同點就是快取的定位應該是一種輔助角色,是一種錦上添花般的存在,

快取也是一把雙刃劍,基于快取可以大幅提升我們的系統并發承壓能力,但稍不留神也可能會讓我們的系統陷入滅頂之災,所以我們在決定使用快取的時候,需要知曉快取設計與使用的一些關鍵要點,才可以讓我們在使用的時候更加游刃有余,

可洗掉重建

可洗掉重建,這是快取與持久化存盤最大的一個差別,快取的定位一定是為了輔助業務處理而生的,也就是說快取有則使用,沒有也不會影響到我們具體的業務運轉,此外,即使我們的快取資料除了問題,我們也可以將其洗掉重建,

這一點在APP類的產品中體現的會比較明顯,比如對于微信APP的快取,就有明確的提示說快取可以洗掉而不會影響其功能使用:

同樣地,我們也可以去放心的清理瀏覽器的快取,而不用擔心清理之后我們瀏覽器或者網頁的功能會出現例外(最多就是需要重新下載或者重建快取資料,速度會有一些慢),

相同的邏輯,在服務端構建的一些快取,也應該具備此特性,比如基于記憶體的快取,當業務行程重啟后,應該有途徑可以將快取重建出來(比如從MySQL中加載資料然后構建快取,或者是快取從0開始基于請求觸發而構建),

有兜底屏障

快取作為高并發類系統中的核心組件,負責抗住大部分的并發請求,一旦快取組件出問題,往往對整個系統會造成毀滅性的打擊,所以我們的快取在實作的時候必須要有充足且完備的兜底自恢復機制,需要做到以下幾點:

  • 關注下快取資料量超出承受范圍的處理策略,比如定好資料的淘汰機制

  • 避免快取集中失效,比如批量加載資料到快取的時候隨機打散過期時間,避免同一時間大批量快取失效引發快取雪崩問題,

  • 有效地冷資料預熱加載機制,以及熱點資料防過期機制,避免出現大量對冷資料的請求無法命中快取或者熱點資料突然失效,導致快取擊穿問題,

  • 合理的防身自保手段,比如采用布隆過濾器機制,避免被惡意請求攻陷,導致快取穿透類的問題,

快取的可靠性與兜底策略設計,是一個宏大且寬泛的命題,在本系列專欄后續的文章中,我們會逐個深入的探討,

關注快取的一致性保證

在高并發類的系統中進行資料更新的時候,快取與資料庫的資料一致性問題,是一個永遠無法繞過的話題,對于基于旁路型快取的大部分業務而言,資料更新操作,一般可以組合出幾種不同的處理策略:

  • 先更新快取,再更新資料庫

  • 先更新資料庫, 再更新快取

  • 先洗掉快取,再更新資料庫

  • 先更新資料庫,再洗掉快取

由于大部分資料庫都支持事務,而幾乎所有的快取操作都不具有事務性,所以在一些寫操作并發不是特別高且一致性要求不是特別強烈的情況下,可以簡單的借助資料庫的事務進行控制,比如先更新資料庫再更新快取,如果快取更新失敗則回滾資料庫事務,

然而在一些并發請求特別高的時候,基于事務控制來保證資料一致性往往會對性能造成影響,且事務隔離級別設定的越高影響越大,所以也可以采用一些其它輔助策略,來替代事務的控制,如重試機制、或異步補償機制、或多者結合方式等,

比如下圖所示的這種策略:

上圖的資料更新處理策略,可以有效地保證資料的最終一致性,降低極端情況可能出現資料不一致的概率,并兜底增加了資料不一致時的自恢復能力,

資料一致性保證作為快取的另一個重要命題,我們會在本系列專欄后續的文章中專門進行深入的剖析,

總結回顧

本篇文章的內容中,我們對快取的各個方面進行了一個簡單的闡述與了解,也可以看出快取對于一個軟體系統的重要價值,通過對快取的合理、充分利用,可以大大的增強我們的系統承壓性能、提升產品的用戶體驗

快取作為高并發系統中的神兵利器被廣泛使用,堪稱高并發系統的基石之一,而快取的內容還遠遠不止我們本篇檔案中所介紹的這些、它是一個非常宏大的命題,

為了能夠將快取的方方面面徹底的講透、講全,在接下來的一段時間里,我會以系列專欄的形式,從不同的角度對快取的方方面面進行探討,不僅僅著眼于如何去使用快取、也一起聊聊快取設計中的一些哲學理念 —— 這一點是我覺得更有價值的一點,因為這些理念對提升我們的軟體架構認知、完善我們的軟體設計思維有很大的指導與借鑒意義,

所以,如果你有興趣,歡迎關注本系列專欄(深入理解快取原理與實戰設計),我會以我一貫的行文風格,用最簡單的語言講透復雜的邏輯,期待一起切磋、共同成長,

我是悟道,聊技術、又不僅僅聊技術~

如果覺得有用,請點贊 + 關注讓我感受到您的支持,也可以關注下我的公眾號【架構悟道】,獲取更及時的更新,

期待與你一起探討,一起成長為更好的自己,

本文來自博客園,作者:架構悟道,歡迎關注公眾號[架構悟道]持續獲取更多干貨,轉載請注明原文鏈接:https://www.cnblogs.com/softwarearch/p/16828094.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/520607.html

標籤:其他

上一篇:Linux 無法寫入權限問題 | Wordpress 不能自動安裝主題、插件

下一篇:RabbitMQ安裝說明檔案(超詳細版本)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more