性能優化 - 案例篇:緩沖區

文章目錄

  • Pre
  • 1. 引言
  • 2. 緩沖概念與類比
  • 3. Java I/O 中的緩沖實現
    • 3.1 FileReader vs BufferedReader:裝飾者模式設計
    • 3.2 BufferedInputStream 源碼剖析
      • 3.2.1 緩沖區大小的權衡與默認值
  • 4. 異步日志中的緩沖:Logback 異步日志原理與配置要點
    • 4.1 Logback 異步日志原理
    • 4.2 核心配置示例
      • 4.2.1 三個關鍵參數
  • 5. 緩沖區設計思路—同步 vs 異步
    • 5.1 同步緩沖
    • 5.2 異步緩沖
  • 6. Kafka 生產者緩沖示例
    • 6.1 Kafka 生產者緩沖原理
    • 6.2 緩沖區丟數據風險
    • 6.3 緩沖區過載與業務可用性
  • 7. 其他緩沖場景與示例
  • 8. 注意事項與異常場景
  • 9. 小結

在這里插入圖片描述


Pre

性能優化 - 理論篇:常見指標及切入點

性能優化 - 理論篇:性能優化的七類技術手段

性能優化 - 理論篇:CPU、內存、I/O診斷手段

性能優化 - 工具篇:常用的性能測試工具

性能優化 - 工具篇:基準測試 JMH


  1. 引言:重溫緩沖本質與設計動機;
  2. 緩沖概念與類比:蓄水池與生產線示例;
  3. Java I/O 中的緩沖實現:
    3.1 FileReader vs BufferedReader,裝飾者模式設計;
    3.2 BufferedInputStream 源碼剖析(fill() 邏輯與緩沖區擴容);
    3.3 緩沖區大小的權衡與默認值(8KB);
  4. 異步日志中的緩沖:Logback 異步日志原理與配置要點(queueSize、maxFlushTime、discardingThreshold);
  5. 緩沖區設計思路—同步 vs 異步:
    5.1 同步緩沖:單線程或方法內批量觸發策略;
    5.2 異步緩沖:生產者策略(拋棄/阻塞/異常)與多線程消費者的同步問題;
  6. Kafka 生產者緩沖示例:batch.size、linger.ms 如何影響消息丟失與可用性;
  7. 其他緩沖場景與示例:StringBuilder/StringBuffer、操作系統網絡緩沖、數據庫 Buffer Pool、ID 生成器緩存;
  8. 注意事項與異常場景:緩沖區數據丟失風險、預寫日志與 WAL 簡述;
  9. 小結:緩沖區優化的收益與權衡;

1. 引言

在 性能優化 - 理論篇:性能優化的七類技術手段 中,已經初步了解“復用優化”領域下的兩大子方向:緩存(Cache)緩沖(Buffer)

接下來我們聚焦于“緩沖”這一個技術手段,深入理解它在 Java 語言與中間件中的各類應用場景,以及在設計時需要注意的權衡與異常處理。


為什么要用緩沖?

  • 設備之間速度差異:CPU/內存讀寫速度?磁盤或網絡 I/O;
  • 頻繁、小量的隨機 I/O 會導致尋道或上下文切換開銷巨大;
  • 緩沖通過在內存中聚合數據,批量順序寫/讀,顯著提高吞吐。

接下來,將從概念、源碼、配置與設計思路幾個維度展開,對“緩沖”有一個系統化的認識。


2. 緩沖概念與類比

緩沖(Buffer)最本質的作用,是將“生產方”與“消費方”之間的不一致速度,化解為一個容量有限的“中間池”。

  • 蓄水池比喻

    • 放水端(消費方):以恒定速率流出,就如程序中讀取緩沖區后進行處理;
    • 進水端(生產方):速率不確定,可能快也可能慢,就如磁盤或網絡向緩沖寫數據;
    • 緩沖區(蓄水池)大小:當進水過快或消費端處理慢時,水就會在池中積累;當池滿時,生產方必須等待或做其他處理。
  • 包餃子流水線

    • 搟皮工序 vs 包餡工序,如果一搟一交彼此就停止,效率低;
    • 加入一個盆子作為中間緩沖,搟皮不斷往盆里扔,包餡者隨時取用,兩者最大限度保持各自節奏。

從宏觀而言,Java 的堆本身也可視作一個“對象緩沖區”——應用線程在其中不斷分配對象,而垃圾回收線程(GC)則以另一種節奏“消費”這些對象。

對比于“緩存(Cache)”,緩沖側重于寫(或讀)過程中的批量與順序,讓慢速設備前端獲得“可持續的小幅流量”。


3. Java I/O 中的緩沖實現

在 Java 中,緩沖最常見的應用場景就是文件與網絡 I/O。底層設備(如磁盤、Socket)本身速度較慢,而 Java I/O 通過裝飾者模式,將原始流包裝為“帶緩沖的流”,讓單次 read()/write() 調用變為“先讀/寫到內存緩沖區,再批量交給底層設備”。

3.1 FileReader vs BufferedReader:裝飾者模式設計

在這里插入圖片描述

  • FileReader:直接從磁盤逐個字符讀取,一次 read() 需要:

    1. 操作系統觸發文件系統尋道,讀取一個字節到內核緩沖;
    2. 再從內核緩沖拷貝到用戶空間;
    3. 返回給應用。

    由于每調用一次 read() 都要重復上述步驟,效率極低。

  • BufferedReader:以 Reader reader = new BufferedReader(new FileReader(path)) 方式包裝后:

    1. 在首次 read() 時,會一次性將后續 buffer.length 個字節(默認 8KB)讀入 Java 堆內存中的 byte[] buffer;
    2. 之后的多次調用 read(),只需從內存 buffer 中讀取字符,直到 pos >= count,才觸發下次 fill()
    3. 大多數情況下,減少了對磁盤和內核空間的多次交互。

    這種添加功能而不修改原類代碼的模式,就是裝飾者(Decorator)模式。

    public class Demo {public int readWithoutBuffer(String path) throws IOException {int result = 0;try (Reader reader = new FileReader(path)) {int value;while ((value = reader.read()) != -1) {result += value;}}return result;}public int readWithBuffer(String path) throws IOException {int result = 0;try (Reader reader = new BufferedReader(new FileReader(path))) {int value;while ((value = reader.read()) != -1) {result += value;}}return result;}
    }
    
    • 如果將兩段代碼用 JMH 對比測試,后者在絕大多數文件大小與硬件環境下,都能以數倍乃至十數倍的速度勝出(未考慮 OS page cache)。

3.2 BufferedInputStream 源碼剖析

BufferedInputStream 為例,下面我們重點關注它的 read()fill() 實現,理解緩沖區如何管理數據。

public synchronized int read() throws IOException {if (pos >= count) {fill();if (pos >= count)return -1;}return getBufIfOpen()[pos++] & 0xff;
}private void fill() throws IOException {byte[] buffer = getBufIfOpen();if (markpos < 0)pos = 0;            /* no mark: throw away the buffer */else if (pos >= buffer.length)  /* no room left in buffer */if (markpos > 0) {  /* can throw away early part of buffer */int sz = pos - markpos;System.arraycopy(buffer, markpos, buffer, 0, sz);pos = sz;markpos = 0;} else if (buffer.length >= marklimit) {markpos = -1;   /* buffer got too big, invalidate mark */pos = 0;        /* drop buffer contents */} else if (buffer.length >= MAX_BUFFER_SIZE) {throw new OutOfMemoryError("Required array size too large");} else {            /* grow buffer */int nsz = (pos <= MAX_BUFFER_SIZE - pos)? pos * 2 : MAX_BUFFER_SIZE;if (nsz > marklimit)nsz = marklimit;byte nbuf[] = new byte[nsz];System.arraycopy(buffer, 0, nbuf, 0, pos);buf = nbuf;buffer = nbuf;}count = pos;int n = getInIfOpen().read(buffer, pos, buffer.length - pos);if (n > 0)count = n + pos;
}
  1. poscount

    • pos:當前緩沖區已經消費到的位置索引;
    • count:緩沖區中實際可用字節數(讀取自底層 InputStream)。
  2. pos >= count 時,調用 fill()

    • 無 mark 邏輯:如果未在流上調用過 mark(),則直接 pos = 0,丟棄舊緩沖區內容;
    • 有 mark 邏輯:如果調用過 mark() 并且 buffer 尚未超過 marklimit,會先將 buffer[markpos, pos) 部分拷貝到 buffer[0, sz),保留標記區域;否則當 buffer 大小接近 marklimit,會放棄緩存并重置 markpos = -1
    • 緩沖區擴容:若 buffer.length < marklimitpos >= buffer.length,則按 pos*2marklimit 的大小擴容,以承載更多數據(最大不超過 MAX_BUFFER_SIZE)。
  3. 從底層流讀取數據

    • 調用 getInIfOpen().read(buffer, pos, buffer.length - pos),一次性將盡量多的數據填入 buffer[pos, buffer.length)
    • 讀取后把 count = pos + n,表示新的緩沖區可讀取字節數。
    • 隨后 read() 方法從內存 buffer 中依次提供單字節給調用者。

這樣,絕大多數 reader.read() 調用都不會觸發一次真正的磁盤或網絡 I/O,而是走內存讀取,直到緩沖耗盡才會調用一次底層的 read(...)


3.2.1 緩沖區大小的權衡與默認值

  • 為什么不一次性把整個文件都讀到緩沖?

    • 緩沖區太小時,需要頻繁地調用 fill(),失去緩沖效果;
    • 緩沖區太大,單次 fill() 就涉及大量內存分配并可能導致垃圾回收壓力;
    • 默認緩沖區大小一般為 8192 字節(8KB),是工業界常見的折中值,既能減少單次 fill() 帶來的系統調用開銷,又不會占用過多堆內存。
  • 調整緩沖區大小的思路

    • 對于小文件或小 HTTP 響應,可將緩沖區設置為 4KB 或更小,減少內存消耗;
    • 對于大文件復制、視頻流處理等場景,可適當增大為 32KB 或 64KB,以減少 I/O 調用頻率;
    • 但文件過大時,緩存整個文件到內存會導致 OOM,因此需結合實際業務與可用堆內存大小,謹慎配置。

4. 異步日志中的緩沖:Logback 異步日志原理與配置要點

在高并發服務中,同步日志會成為性能瓶頸:

  • 每次調用 logger.info(...) 都要先拼接日志消息,再調用底層 I/O 將文本寫入磁盤;
  • 如果并發量大,業務線程在等待磁盤 I/O 完成時被阻塞,整體延遲顯著增加;
  • 即便日志輸出到控制臺,也會占用 CPU 時間來格式化。這時可以引入“異步日志”來解耦業務線程與磁盤寫入。

4.1 Logback 異步日志原理

Logback 的異步日志基于 AsyncAppender,其核心思路:

  1. 業務線程(生產者):調用 logger 時,只需將待寫入的日志事件先放入內存中的阻塞隊列(ArrayBlockingQueue);
  2. 異步 Worker 線程(消費者):在后臺單線程循環不斷地從隊列 poll() 日志事件,然后批量地將它們寫入磁盤。

這樣,業務線程僅關心向緩沖隊列“放入”日志,I/O 寫入由獨立線程異步完成。

在這里插入圖片描述

4.2 核心配置示例

logback.xml 中添加如下內容:

<!-- 定義一個 FileAppender,負責將日志寫入磁盤 -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender"><file>app.log</file><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder>
</appender><!-- 定義一個 AsyncAppender,將日志事件緩沖到隊列 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"><!-- 當隊列中的事件數量達到 discardingThreshold 時,可以丟棄低級別日志 --><discardingThreshold>0</discardingThreshold><!-- 隊列大小:最多容納 512 條事件 --><queueSize>512</queueSize><!-- 指定要異步包裝的目標 appender --><appender-ref ref="FILE"/>
</appender><root level="INFO"><!-- 使用異步日志器 --><appender-ref ref="ASYNC"/>
</root>

4.2.1 三個關鍵參數

  1. queueSize(隊列容量)

    • 默認值為 256;當待寫入事件數量超過 queueSize 時,生產者線程會根據 discardingThreshold 策略進行處理;
    • 如果設置過大,進程突然斷電,隊列內未落盤的日志全部丟失風險增大;
  2. discardingThreshold(丟棄閾值)

    • 取值范圍 0 <= discardingThreshold <= queueSize
    • 當隊列長度 ≥ discardingThreshold 時,低于或等于設定級別的日志事件可被丟棄,以保護高優先級日志;
    • 默認值為 queueSize × 0.8,即隊列達到 80% 時開始丟棄低級別日志;若設置為 0,則不丟棄任何事件,但可能導致生產者阻塞或拋出異常;
  3. maxFlushTime(關閉時最長等待時間)

    • 當應用優雅關閉時,AsyncAppender 會調用 worker.join(maxFlushTime),等待后臺線程將剩余日志寫完;
    • 如果等待超時,應用仍會強制退出,此時緩沖區中未落盤的日志將丟失;
    • 合理設置該值(如 5 秒或 10 秒),在性能與丟失風險之間權衡。

5. 緩沖區設計思路—同步 vs 異步

緩沖區優化常見于需要對“生產端”和“消費端”解耦的場景。但在設計時,需要考慮“同步緩沖”與“異步緩沖”兩種模式,取舍點在于編程模型復雜度與性能收益。

在這里插入圖片描述

5.1 同步緩沖

  • 模型示意

    生產者 →→ [緩沖區] →→ 消費者
    

在這里插入圖片描述

整個過程在同一個線程或調用鏈中執行。常見策略:

  1. 閾值觸發寫入:當緩沖區積累元素數量 ≥ flushThreshold,或累積字節數 ≥ byteThreshold 時,一次性批量寫入底層資源;
  2. 定時觸發寫入:如果緩沖區在 maxIdleTime 內未達到 flushThreshold,則定時將已有數據寫出,保證高延遲數據得以及時消費;
  • 優缺點

    • 優點:編程模型直觀、邏輯簡單,無額外線程;
    • 缺點:當底層寫入耗時出現波動(如突發磁盤抖動),會阻塞生產者線程,導致整體響應能力下降。
  • 示例

    • 字符串拼接時使用 StringBuilder,一次性將多次 append() 的結果通過 toString() 寫入磁盤;
    • JDBC 批量插入:在內存中將多條 SQL 語句緩存在 PreparedStatement 中,達到 batchSize 時通過 executeBatch() 一次性寫入數據庫。

5.2 異步緩沖

  • 模型示意

    生產者(線程 A) →→ [緩沖區(隊列)] →→ 消費者(后臺線程 B)
    

在這里插入圖片描述

生產者僅負責往緩沖區寫入;消費者由獨立線程不斷從緩沖區讀取并寫出。

  • 生產者策略

    1. 阻塞:當隊列已滿,生產者調用 put() 時會阻塞,直到有空位;
    2. 非阻塞失敗:調用 offer(),若緩沖區已滿則返回 false,讓上層邏輯根據返回值做重試或丟棄;
    3. 異常拋出:直接在 put() 或自定義方法中拋出 RejectedExecutionException 等,通知調用方“緩沖已滿”;
    4. 回調機制:在生產者線程注冊回調,當數據真正被消費后才觸發,也可以用于跟蹤已消費數據。
  • 消費者設計

    • 啟動單線程或線程池,不斷從隊列 poll() 數據;
    • 處理邏輯應考慮批量拉取,以減少 I/O 寫入次數,例如 drainTo()
    • 若消費者處理速度不足,隊列會持續積壓;生產者需根據業務側容忍值判斷是否阻塞或快速失敗。
  • 多消費者與同步問題

    • 當緩沖區被多個消費者并發讀寫時,需要保證數據順序或一致性;
    • 可使用有序隊列(如基于 BlockingQueue)或根據分區(Partition)分流;
    • 同時考慮多個消費者線程各自的吞吐能力與負載均衡。

6. Kafka 生產者緩沖示例

Kafka 生產者客戶端的“批量發送”與“緩沖區”設計。下面以常見參數 batch.sizelinger.ms 為例,說明緩沖區對性能與可靠性的影響。

在這里插入圖片描述

6.1 Kafka 生產者緩沖原理

  • batch.size(字節):指定針對每個 partition 為單個批次消息設置的最大字節容量,默認為 16KB。當該容量被填滿后,生產者立即將該 batch 發送給對應的 broker。
  • linger.ms(毫秒):指定“批次最大等待時間”,即在 batch.size 未被填滿的情況下,生產者也會等待 linger.ms 后把已積累的消息強制發送,以減少每條消息都立刻網絡發送帶來的開銷。

具體流程:

  1. 當調用 producer.send(record) 時,Kafka 生產者客戶端先把 record 序列化后放入對應 partition 的緩沖隊列(內存);
  2. 如果當前 batch 的累積字節數 ≥ batch.size,則立即觸發發送;
  3. batch.size 未滿,且當前時間超過 linger.ms,也會把已累積消息發送;
  4. 發送出發后會異步等待 broker ACK 確認或重試。

6.2 緩沖區丟數據風險

假設生產者程序發生以下情況:

  • 機器突然斷電
  • JVM 進程被 kill -9 殺死

此時如果緩沖隊列中仍有尚未被 send() 到 Broker 或未獲 ACK 的消息,全部會丟失。默認情況下,緩沖區大小為 16KB,如果生產方業務持續產生大量消息,且 broker 短暫不可用,就會導致緩沖區快速填滿。

解決方案:

  1. 縮小 batch.size:使得緩沖隊列更頻繁地發送,雖然犧牲吞吐量,但可減少丟失概率;
  2. 降低 linger.ms:即使在低流量情況下,也會在較短等待后發送,保證消息盡快到達 broker;
  3. 開啟冪等性與 ACK 配置:設置 enable.idempotence=true 并且 acks=all,讓 broker 等待所有 ISR(in-sync replicas)確認后再 ACK,確保至少寫入一個副本或多副本;
  4. 生產者寫入前落盤預寫日志:在生產者本地先記錄“即將發送的消息”,待發送成功后再刪除,重啟后可根據預寫日志補發;
  5. 使用電池或 UPS:在極端斷電場景下保證機器有足夠時間將緩沖持久化到磁盤。

6.3 緩沖區過載與業務可用性

當 broker 暫時不可用或網絡抖動時,生產者緩沖區會不斷積累消息,直至達到 buffer.memory(內存緩沖池)或達成 max.block.ms,此時默認行為是阻塞調用線程。若業務對等待較敏感,可能導致線程被長時間阻塞,最終耗盡線程池資源,從而引起整個服務不可用。

可選對策:

  • 調整 max.block.ms:一旦超時則拋出 TimeoutException 告知調用方“消息積壓,發送超時”;
  • 限流策略:在業務層做流控(如令牌桶),防止短時間內壓入大量消息;
  • 異步重試:將消息暫存在本地隊列或數據庫,后臺線程定時重試投遞;

7. 其他緩沖場景與示例

除了文件 I/O 與消息中間件,緩沖思想在常見的 Java 開發中無處不在:

  1. StringBuilder / StringBuffer

    • 在 Java 中,頻繁使用 String 做拼接會產生大量臨時對象;
    • StringBuilder 通過在內存中維護一個 char[] 緩沖,每次 append() 寫入緩沖中,最后一次性 toString() 時整體創建一個 String,顯著提高拼接性能。
  2. 操作系統網絡緩沖(SO_SNDBUF / SO_RCVBUF)

    • TCP Socket 在內核中會分配發送與接收緩沖區大小,可通過 socket.setSendBufferSize(...) / socket.setReceiveBufferSize(...) 進行調優;
    • 適當增大操作系統緩沖區,可應對應用端瞬時突發流量,減少 packet drop;但過大會占用更多內核內存。
  3. 數據庫 InnoDB Buffer Pool

    • MySQL InnoDB 存儲引擎通過 innodb_buffer_pool_size 配置,將數據頁和索引頁緩存在內存中,減少磁盤讀取;
    • 合理將 buffer_pool_size 設置為物理內存的 60%~80%,能顯著提升查詢和寫入性能。
  4. ID 生成器緩存

    • 常見的全局遞增 ID 生成,如 Twitter Snowflake 或數據庫自增 ID,為了減少每次網絡交互,往往將一段 ID(如 1000 個)一次性從數據庫或中央服務拉取到本地緩沖;
    • 應用只需從本地緩沖取得下一個 ID,當耗盡后再異步從中央服務拉取下一段,減少延遲。

8. 注意事項與異常場景

雖然緩沖區能帶來明顯性能提升,但在設計時還要考慮以下幾方面的風險與權衡:

  1. 緩沖區數據丟失

    • 突發斷電、kill -9 等強制銷毀進程時,緩沖區中的數據尚未落盤或未發送,全部丟失;
    • 對金融、訂單類等對數據可靠性要求極高的系統,可通過“先寫 WAL 日志再入緩沖”來保證數據不丟;
  2. 緩沖區內存占用與 OOM

    • 大容量緩沖區占用堆內存較大,可能導致垃圾回收壓力增大或堆內存不足;
    • 需根據可用物理內存與業務吞吐量合理設置,如 8KB64KB、512MB2GB 等;
  3. 順序與一致性問題

    • 在多線程/多消費者場景下,若需要保證“消息順序”,必須使用單隊列或分區隊列;
    • 對于都依賴同一緩存狀態的讀寫,需要在并發消費者之間做好狀態一致性或加鎖、防重入等處理;
  4. 性能收益遞減

    • 緩沖區過小則頻繁交互;過大則內存占用過高;需要在吞吐與延遲之間做折中;
    • 在高并發網絡場景,Socket / OS 層面也會加入多級緩沖,需要一體化考慮。
  5. 預寫日志與數據恢復

    • 常見做法是在寫入緩沖前,先將關鍵元數據(例如 Kafka 消息 key)寫到本地磁盤日志;待緩沖數據真正被提交到 broker 后,再標記該日志為成功。重啟后掃描日志,補發未成功消息。
    • 這種“先 WAL 后緩存”的策略會帶來額外寫盤開銷,需要衡量業務對丟失率的容忍度。

9. 小結

系統地探討了**緩沖(Buffer)**在 Java 語言與中間件中的典型應用:

  1. 緩沖本質與類比

    • 緩沖區是解耦生產者與消費者速度差異的內存“蓄水池”;
    • 讓慢速設備接收“小而頻繁” → “大而順序” 的 I/O 請求,大幅提高吞吐。
  2. Java I/O 緩沖實現

    • BufferedReader / BufferedInputStream 通過 fill() 方法一次性從底層流讀入 8KB(默認)數據到內存;
    • 通過 poscount 指針管理緩沖區消費位置;自動擴容至 marklimit,在保證性能的同時兼容 mark()/reset()
  3. 異步日志緩沖

    • Logback AsyncAppender 將日志事件先緩存在 ArrayBlockingQueue 中,后臺線程異步寫入磁盤;
    • 重要參數:queueSize(隊列容量)、discardingThreshold(丟棄閾值)、maxFlushTime(關閉時等待時間)。
  4. 緩沖設計思路—同步 vs 異步

    • 同步緩沖:批量觸發策略簡單,但會阻塞生產者;
    • 異步緩沖:解耦寫入與消費,需設計生產者滿載后的處理策略與多消費者同步。
  5. Kafka 生產者緩沖示例

    • 通過 batch.size + linger.ms 實現消息批量發送;
    • 緩沖區滿或超時觸發網絡發送,帶來吞吐與延遲權衡;
    • 在斷電或 kill -9 場景下,緩沖中消息或未獲 ACK 消息會丟失,可結合寫盤預寫日志或副本策略降低風險。
  6. 其他緩沖場景

    • StringBuilderStringBuffer 字符串拼接;
    • 操作系統 Socket 緩沖(SO_SNDBUF/SO_RCVBUF);
    • 數據庫 InnoDB Buffer Pool;
    • ID 生成器段緩存等。
  7. 注意事項與異常場景

    • 緩沖區丟失風險、內存占用風險;
    • 順序一致性與并發讀寫沖突;
    • 性能收益遞減點;
    • WAL/預寫日志策略平衡可靠性與性能。

總之,緩沖區優化是 Java 性能優化中一項非常重要的技術手段,它既能顯著提高磁盤與網絡 I/O 吞吐,也帶來了異步設計下的編程復雜度與故障恢復挑戰。

在實際項目中,應結合業務對“數據丟失概率”與“延遲/吞吐”之間的容忍度,合理設置緩沖大小與處理策略。


在這里插入圖片描述

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

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

相關文章

文檔整合自動化

主要功能是按照JSON文件&#xff08;Sort.json&#xff09;中指定的順序合并多個Word文檔&#xff08;.docx&#xff09;&#xff0c;并清除文檔中的所有超鏈接。最終輸出合并后的文檔名為"sorted_按章節順序.docx"。 主要分為幾個部分&#xff1a; 初始化配置 定…

嵌入式(C語言篇)Day13

嵌入式Day13 一段話總結 文檔主要介紹帶有頭指針和尾指針的單鏈表的實現及操作&#xff0c;涵蓋創建、銷毀、頭插、尾插、按索引/數據增刪查、遍歷等核心操作&#xff0c;強調頭插/尾插時間復雜度為O(1)&#xff0c;按索引/數據操作需遍歷鏈表、時間復雜度為O(n)&#xff0c;并…

【ASR】基于分塊非自回歸模型的流式端到端語音識別

論文地址:https://arxiv.org/abs/2107.09428 摘要 非自回歸 (NAR) 模型在語音處理中越來越受到關注。 憑借最新的基于注意力的自動語音識別 (ASR) 結構,與自回歸 (AR) 模型相比,NAR 可以在僅精度略有下降的情況下實現有前景的實時因子 (RTF) 提升。 然而,識別推理需要等待…

RNN循環網絡:給AI裝上“記憶“(superior哥AI系列第5期)

&#x1f504; RNN循環網絡&#xff1a;給AI裝上"記憶"&#xff08;superior哥AI系列第5期&#xff09; 嘿&#xff01;小伙伴們&#xff0c;又見面啦&#xff01;&#x1f44b; 上期我們學會了讓AI"看懂"圖片&#xff0c;今天要給AI裝上一個更酷的技能——…

DAY41 CNN

可以看到即使在深度神經網絡情況下&#xff0c;準確率仍舊較差&#xff0c;這是因為特征沒有被有效提取----真正重要的是特征的提取和加工過程。MLP把所有的像素全部展平了&#xff08;這是全局的信息&#xff09;&#xff0c;無法布置到局部的信息&#xff0c;所以引入了卷積神…

【仿生系統】愛麗絲機器人的設想(可行性優先級較高)

非程序化、能夠根據環境和交互動態產生情感和思想&#xff0c;并以微妙、高級的方式表達出來的能力 我們不想要一個“假”的智能&#xff0c;一個僅僅通過if-else邏輯或者簡單prompt來模擬情感的機器人。您追求的是一種更深層次的、能夠學習、成長&#xff0c;并形成獨特“個性…

面向連接的運輸:TCP

目錄 TCP連接 TCP報文段結構 往返時間估計與超時 可靠數據傳輸 回退N步or超時重傳 超時間隔加倍 快速重傳 流量控制 TCP連接管理 三次握手 1. 客戶端 → 服務器&#xff1a;SYN 包 2. 服務器 → 客戶端&#xff1a;SYNACK 包 3. 客戶端 → 服務器&#xff1a;AC…

SpringAI系列 - 升級1.0.0

目錄 一、調整pom二、MessageChatMemoryAdvisor調整三、ChatMemory get方法刪除lastN參數四、QuestionAnswerAdvisor調整Spring AI發布1.0.0正式版了?? ,搞起… 一、調整pom <properties><java.version>17</java.version><spring-ai.version>

前端高頻面試題2:JavaScript/TypeScript

1.什么是類數組對象 一個擁有 length 屬性和若干索引屬性的對象就可以被稱為類數組對象&#xff0c;類數組對象和數組類似&#xff0c;但是不能調用數組的方法。常見的類數組對象有 arguments 和 DOM 方法的返回結果&#xff0c;還有一個函數也可以被看作是類數組對象&#xff…

Spring Security入門:創建第一個安全REST端點項目

項目初始化與基礎配置 創建基礎Spring Boot項目 我們首先創建一個名為ssia-ch2-ex1的空項目(該名稱與配套源碼中的示例項目保持一致)。項目需要添加以下兩個核心依賴: org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-secur…

秋招Day12 - 計算機網絡 - UDP

說說TCP和UDP的區別&#xff1f; TCP使用無邊界的字節流傳輸&#xff0c;可能發生拆包和粘包&#xff0c;接收方并不知道數據邊界&#xff1b;UDP采用數據報傳輸&#xff0c;數據報之間相互獨立&#xff0c;有邊界。 應用場景方面&#xff0c;TCP適合對數據的可靠性要求高于速…

【QQ音樂】sign簽名| data參數加密 | AES-GCM加密 | webpack (下)

1.目標 網址&#xff1a;https://y.qq.com/n/ryqq/toplist/26 我們知道了 sign P(n.data)&#xff0c;其中n.data是明文的請求參數 2.webpack生成data加密參數 那么 L(n.data)就是密文的請求參數。返回一個Promise {<pending>}&#xff0c;所以L(n.data) 是一個異步函數…

Codeforces Round 1028 (Div. 2)(A-D)

題面鏈接&#xff1a;Dashboard - Codeforces Round 1028 (Div. 2) - Codeforces A. Gellyfish and Tricolor Pansy 思路 要知道騎士如果沒了那么這個人就失去了攻擊手段&#xff0c;貪心的來說我們只需要攻擊血量少的即可&#xff0c;那么取min比較一下即可 代碼 void so…

【存儲基礎】存儲設備和服務器的關系和區別

文章目錄 1. 存儲設備和服務器的區別2. 客戶端訪問數據路徑場景1&#xff1a;經過服務器處理場景2&#xff1a;客戶端直連 3. 服務器作為"中轉站"的作用 剛開始接觸存儲的時候&#xff0c;以為數據都是存放在服務器上的&#xff0c;服務器和存儲設備是一個東西&#…

macOS 安裝 Grafana + Prometheus + Node Exporter

macOS 安裝指南&#xff1a;Grafana Prometheus Node Exporter 目錄簡介&#x1f680; 快速開始 安裝 Homebrew1. 安裝 Homebrew2. 更新 Homebrew 安裝 Node Exporter使用 Homebrew 安裝驗證 Node Exporter 安裝 Prometheus使用 Homebrew 安裝驗證安裝 安裝 Grafana使用 Home…

不可變集合類型轉換異常

記錄一個異常&#xff1a;class java.util.ImmutableCollections$ListN cannot be cast to class java.util.ArrayList (java.util.ImmutableCollections$ListN and java.util.ArrayList 文章目錄 1、原因2、解決方式一3、解決方式二4、關于不可變集合的補充4.1 JDK8和9的對比4…

【DAY37】早停策略和模型權重的保存

內容來自浙大疏錦行python打卡訓練營 浙大疏錦行 知識點&#xff1a; 過擬合的判斷&#xff1a;測試集和訓練集同步打印指標模型的保存和加載 僅保存權重保存權重和模型保存全部信息checkpoint&#xff0c;還包含訓練狀態 早停策略 作業&#xff1a; 對信貸數據集訓練后保存權…

【Zephyr 系列 3】多線程與調度機制:讓你的 MCU 同時干多件事

好的,下面是Zephyr 系列第 3 篇:聚焦 多線程與調度機制的實踐應用,繼續面向你這樣的 Ubuntu + 真板實戰開發者,代碼清晰、講解通俗、結構規范,符合 CSDN 高質量博客標準。 ??關鍵詞:Zephyr、線程調度、k_thread、k_sleep、RTOS、BluePill ??適合人群:想從裸機開發進…

實現RabbitMQ多節點集群搭建

目錄 引言 一、環境準備 二、利用虛擬機搭建 ? 三、鏡像集群配置 四、HAProxy實現負載均衡(主用虛擬機操作) 五、測試RabbitMQ集群搭建情況 引言 在現代分布式系統中&#xff0c;消息隊列&#xff08;Message Queue&#xff09;扮演著至關重要的角色,而 RabbitMQ 作為…

異步上傳石墨文件進度條前端展示記錄(采用Redis中String數據結構實現-蘇東坡版本)

昔者&#xff0c;有客臨門&#xff0c;亟需自石墨文庫中擷取卷帙若干。此等文冊&#xff0c;非止一卷&#xff0c;乃累牘連篇&#xff0c;亟需批量轉置。然吾輩慮及用戶體驗&#xff0c;當效東坡"腹有詩書氣自華"之雅意&#xff0c;使操作如行云流水&#xff0c;遂定…