【OD機試題解法筆記】文件緩存系統

題目描述

請設計一個文件緩存系統,該文件緩存系統可以指定緩存的最大值(單位為字節)。
文件緩存系統有兩種操作:

  • 存儲文件(put)
  • 讀取文件(get)

操作命令為:

  • put fileName fileSize
  • get fileName

存儲文件是把文件放入文件緩存系統中;
讀取文件是從文件緩存系統中訪問已存在,如果文件不存在,則不作任何操作。
當緩存空間不足以存放新的文件時,根據規則刪除文件,直到剩余空間滿足新的文件大小位置,再存放新文件。
具體的刪除規則為:文件訪問過后,會更新文件的最近訪問時間和總的訪問次數,當緩存不夠時,按照第一優先順序為訪問次數從少到多,第二順序為時間從老到新的方式來刪除文件。

輸入描述
第一行為緩存最大值 m(整數,取值范圍為 0 < m ≤ 52428800)
第二行為文件操作序列個數 n(0 ≤ n ≤ 300000)
從第三行起為文件操作序列,每個序列單獨一行,文件操作定義為:

op file_name file_size

file_name 是文件名,file_size 是文件大小

輸出描述
輸出當前文件緩存中的文件名列表,文件名用英文逗號分隔,按字典順序排序,如:

a,c

如果文件緩存中沒有文件,則輸出NONE

備注

  1. 如果新文件的文件名和文件緩存中已有的文件名相同,則不會放在緩存中
  2. 新的文件第一次存入到文件緩存中時,文件的總訪問次數不會變化,文件的最近訪問時間會更新到最新時間
  3. 每次文件訪問后,總訪問次數加1,最近訪問時間更新到最新時間
  4. 任何兩個文件的最近訪問時間不會重復
  5. 文件名不會為空,均為小寫字母,最大長度為10
  6. 緩存空間不足時,不能存放新文件
  7. 每個文件大小都是大于 0 的整數

用例1
輸入:

50
6
put a 10
put b 20
get a
get a
get b
put c 30

輸出:

a,c

用例2
輸入:

50
1
get file

輸出:

NONE

思考

輸入有讀取和存儲兩個操作。定義集合 fileSet 存儲文件名稱,哈希表 fileSizeMap 存儲映射每個文件的大小,key 是文件名,value 是文件大小,readFreqMap 存儲映射每個文件的讀取頻次,priorityQueue 維護一個文件名隊列,每次出隊的都是最久未被讀取的文件名。 讀取操作:如果讀取的文件不存在,就不執行任何操作;如果文件存在就給該文件的訪問頻次+1,同時調整優先隊列,把讀取的文件名移到隊尾,每次這樣操作,隊首的文件一定的最久未被訪問的文件。存儲操作:每次存儲文件判斷文件名是否存在,存在就不執行操作;如果不存在,判斷剩余存儲空間 leftSize 是否大于等于當前文件大小,如果不滿足就要刪除讀取頻次最少且最久未被訪問的文件,更新 leftSize += deleteFileSize,循環執行此操作直到滿足存儲需求,如果文件都刪完了還是不滿足就不執行任何操作。存儲文件到 fileSet 中,更新 leftSize -= newFileSize,題目要求存儲新文件也要更新最新訪問時間,那么我們就把新文件名加到優先隊列的隊尾,優先隊列隊尾文件名始終表示最新訪問的文件。刪除操作:首先查找訪問頻次最少的文件名,如果只有一個最少的訪問頻次,直接刪這個文件就對了。如果有多個相同的最少訪問頻次文件名,需要進一步在其中找到最久未被訪問的文件,顯然由于每次優先隊列的隊尾都是更新最新訪問時間的文件名,隊首的文件就是最久未被訪問的,遍歷優先隊列找到最少訪問頻次文件集合中包含當前文件名的文件中止循環,刪除該文件。為什么還遍歷隊列匹配最少訪問頻次集合中的文件?難道隊列隊首文件名可能不在最少訪問頻次文件集合中?有可能的,雖然隊首文件名是最久未被訪問的,但是未必就是訪問頻次最少的文件,假如有個文件 a 在歷史訪問記錄中達到了100次,接著存儲了一個新文件 b,這時候文件 b 是最新訪問的文件,存在隊尾,那么 顯然 a 是存在隊首的最久未被訪問的文件,但它的訪問頻率達到100次,b 只有一次,顯然不能直接刪除隊首元素 a 。由于 JavaScript 沒有優先隊列 API,如果不熟悉,做題的時候寫個正確的優先隊列數據結構也不容易,因此我先用 JS 數組模擬優先隊列的特性實現這個算法,實際能在有效時間內通過所有測試用例才是最重要的。然后提供一個 JS 版二叉堆實現的優先隊列版本代碼。

算法過程(哈希表+數組模擬優先隊列)

  1. 數據結構

    • fileSet記錄緩存中的文件;fileSizesMap存儲文件大小;readFreqMap記錄訪問次數;priorityQueue(數組)按訪問時間排序(最新訪問在末尾)。
    • leftSize追蹤剩余緩存空間。
  2. 核心操作

    • put操作
      • 若文件已存在,直接跳過。
      • 若緩存空間不足,按規則淘汰文件:先篩選訪問次數最少的文件列表,再從列表中刪除priorityQueue中最早出現(最久未訪問)的文件,直到空間足夠。
      • 空間足夠時,新增文件至緩存,初始化訪問次數為0,加入priorityQueue末尾。
    • get操作
      • 若文件存在,訪問次數+1,從priorityQueue中移除后重新加入末尾(更新為最新訪問)。
  3. 結果輸出
    緩存中的文件按字典排序,空則輸出NONE

時間復雜度

  • 單次put操作
    • 淘汰文件時,遍歷查找最少訪問次數文件的時間為O(k)k為當前緩存文件數),最壞情況下需淘汰k次,總復雜度為O(k2)
    • 新增文件為O(1)
  • 單次get操作
    • 查找并移動文件在priorityQueue中的位置為O(k)
  • 整體復雜度
    設操作總數為n,單個操作涉及的最大文件數為k(≤緩存可容納的最大文件數),總時間復雜度為O(n·k2)
    (注:因k通常遠小于n,實際性能可接受,尤其適合中小規模操作場景。)

參考代碼(Least Frequence Used + JS 數組模擬優先隊列)

function solution(totalSize, operations) {const fileSet = new Set();const fileSizesMap = new Map();const readFreqMap = new Map();const priorityQueue = [];let leftSize = totalSize;for (const operation of operations) {const [op, fileName, fileSize] = operation;if (op === 'put') {if (fileSet.has(fileName)) {continue;}// 緩存不夠,要刪文件while (leftSize - fileSize < 0 && priorityQueue.length) {let count = Infinity;let toDeleteList = [];for (let [k, v] of readFreqMap) { // 查找訪問頻率最少的文件if (v < count) {toDeleteList = [k];count = v;} else if (v === count) {toDeleteList.push(k);}}if (toDeleteList.length === 1) { // 如果找到一個訪問頻率最少的文件直接刪除fileSet.delete(toDeleteList[0]);const delSize =  fileSizesMap.get(toDeleteList[0]);leftSize += delSize;readFreqMap.delete(toDeleteList[0]);let index = priorityQueue.indexOf(toDeleteList[0]);priorityQueue.splice(index, 1);} else { // 多個訪問頻率最少的文件需要篩選最久未被訪問的文件,然后刪除for (let i = 0; i < priorityQueue.length; i++) {if (toDeleteList.includes(priorityQueue[i])) {let deleteFileName = priorityQueue[i];fileSet.delete(deleteFileName);const delSize =  fileSizesMap.get(deleteFileName);leftSize += delSize;priorityQueue.splice(i, 1);readFreqMap.delete(deleteFileName);break;}}}        }if (leftSize - fileSize >= 0) {fileSet.add(fileName);fileSizesMap.set(fileName, fileSize);readFreqMap.set(fileName, 0);priorityQueue.push(fileName);leftSize -= fileSize;console.log('leftSize: ', leftSize, ' fileSize: ', fileSize);}} else { // getif (fileSet.has(fileName)) {readFreqMap.set(fileName, readFreqMap.get(fileName) + 1);  // 更新訪問頻率let index = priorityQueue.indexOf(fileName);if (index !== -1) {priorityQueue.splice(index, 1);}priorityQueue.push(fileName); // 移到訪問隊列隊首,表示最新訪問的文件        }}}const fileList = Array.from(fileSet);fileList.sort();let result = "NONE";if (!fileList.length) {console.log("NONE");return "NONE";}result = fileList.join(',');console.log(result);return result;
}const cases = [`50
6
put a 10
put b 20
get a
get a
get b
put c 30`, `50
1
get file`
];let caseIndex = 0;
let lineIndex = 0;const readline = (function () {let lines = [];return function () {if (lineIndex === 0) {lines = cases[caseIndex].trim().split("\n").map((line) => line.trim());}return lines[lineIndex++];};
})();cases.forEach((_, i) => {caseIndex = i;lineIndex = 0;// console.time(`${i} cost time`);solution();// console.timeEnd(`${i} cost time`);  console.log('-------');
});

算法過程(優先隊列)

  1. 數據結構

    • 核心使用MinPriorityQueue(最小優先隊列,基于堆實現)存儲文件信息,堆的比較規則為“訪問次數少優先,次數相同則時間早優先”。
    • _cache(Map)快速映射文件名到文件詳情(大小、訪問次數、時間戳);_usedSize記錄已用緩存空間;_timeCount生成唯一時間戳。
  2. 核心操作

    • put操作
      • 若文件已存在或大小超緩存上限,直接跳過。
      • 若緩存空間不足,循環刪除堆頂元素(優先級最高的待淘汰文件),直到空間足夠。
      • 新增文件至_cache和堆,初始化訪問次數為0,更新時間戳和已用空間。
    • get操作
      • 若文件存在,先從堆中刪除該文件(通過替換+堆調整實現),再更新其訪問次數和時間戳,重新加入堆。
  3. 堆調整細節

    • 中間刪除元素時,用堆尾元素替換目標位置,再通過swim(上浮)和sink(下沉)確保堆結構正確。
    • 堆頂始終是“訪問次數最少且最久未訪問”的文件,淘汰時直接刪除堆頂。
  4. 結果輸出
    緩存中的文件按字典排序,空則輸出NONE

時間復雜度

  • 單次put操作
    • 入隊(enqueue)和出隊(dequeue)均為堆操作,時間復雜度O(log k)k為當前緩存文件數)。
    • 最壞情況下需淘汰k個文件,總復雜度O(k·log k)
  • 單次get操作
    • 查找文件在堆中的位置為O(k),刪除并重新入隊為O(log k),總復雜度O(k + log k)
  • 整體復雜度
    設操作總數為n,總時間復雜度為O(n·k·log k)k為緩存中最大文件數)。
    (注:堆優化了淘汰階段的查找效率,相比數組模擬的O(k2),在大k場景下性能更優。)

參考代碼(Least Frequence Used + 最小優先隊列)

class MinPriorityQueue {constructor(compare) {this._data = [];this._compare = compare || ((a, b) => a - b);}enqueue(e) {this._data.push(e);this.swim(this._data.length-1);}dequeue() {if (this.isEmpty()) return null;const last = this._data.pop();if (this._data.length > 0) {this._data[0] = last;this.sink(0);}}swim(index) {while (index > 0) {let parentIndex = Math.floor((index - 1) / 2);if (this._compare(this._data[index], this._data[parentIndex]) < 0) {[this._data[parentIndex], this._data[index]] = [this._data[index],this._data[parentIndex],];index = parentIndex;continue;}break;}}// 從指定索引開始下沉sink(index) {const n = this._data.length;while (true) {let left = 2 * index + 1;let right = left + 1;let smallest = index;if (left < n && this._compare(this._data[left], this._data[index]) < 0) {smallest = left;}if (right < n && this._compare(this._data[right], this._data[smallest]) < 0) {smallest = right;}if (smallest !== index) {[this._data[smallest], this._data[index]] = [this._data[index],this._data[smallest],];index = smallest;continue;}break;}}front() {return this._data[0];}isEmpty() {return this._data.length === 0;}size() {return this._data.length;}
}class LFUCacheSystem {constructor(capibility) {this._capibility = capibility; // 最大緩存大小this._usedSize = 0; // 當前使用的緩存大小this._cache = new Map();this._minHeap = new MinPriorityQueue((a, b) => { // 傳入自定義比較函數if (a.accessCount === b.accessCount) {return a.lastAccessTime - b.lastAccessTime; // 訪問頻次相同再比較訪問時間}return a.accessCount - b.accessCount;});this._timeCount = 0;}put(fileName, fileSize) {if (fileSize > this._capibility) return;if (this._cache.has(fileName)) { // 如果文件已存在,更新文件的訪問時間return;}// 緩存不夠用了,從最小優先隊列中刪除優先級最高的文件(訪問頻次最少且最久未被訪問的文件)while (fileSize + this._usedSize > this._capibility) {const toDelete = this._minHeap.front();if (toDelete) {this._minHeap.dequeue();  // 刪除文件this._cache.delete(toDelete.fileName);this._usedSize -= toDelete.size; // 更新可用緩存大小}}const currentTime = this._timeCount++;const file = { fileName, size: fileSize, accessCount: 0, lastAccessTime: currentTime };this._minHeap.enqueue(file);this._cache.set(fileName, file);this._usedSize += file.size;}get(fileName) {if (!this._cache.has(fileName)) return;const file = this._cache.get(fileName);this._removeFileFromHeap(fileName);file.accessCount++;file.lastAccessTime = this._timeCount++;this._minHeap.enqueue(file);}_removeFileFromHeap(fileName) {const index = this._minHeap._data.findIndex(item => item.fileName === fileName);if (index === -1) return;// 用最后一個元素替換目標元素const last = this._minHeap._data[this._minHeap._data.length-1];this._minHeap._data[index] = last;this._minHeap._data.pop();if (index < this._minHeap._data.length) {this._minHeap.swim(index);this._minHeap.sink(index);}}getFileList() {const fileList = Array.from(this._cache.keys());fileList.sort();return fileList;}
};function solution2(totalSize, ops) {const cacheSys = new LFUCacheSystem(totalSize);for (const op of ops) {const [operation, fileName, fileSize] = op;if (operation === 'put') {cacheSys.put(fileName, parseInt(fileSize));} else { // getcacheSys.get(fileName);}}const fileList = cacheSys.getFileList();let result = "NONE";if (!fileList.length) {console.log("NONE");return "NONE";}result = fileList.join(',');console.log(result);return result;
}function entry() {const totalSize = parseInt(readline());const n = parseInt(readline());const ops = [];for (let i = 0; i < n; i++) {const [op, fileName, fileSize] = readline().split(' ');ops.push([op, fileName, parseInt(fileSize)]);}// console.log('case: totalSize  n  ops ', totalSize, n, ops);// solution1 // const result = solution(totalSize, ops);// solution2const result2 = solution2(totalSize, ops);// console.log(result === result2);}const cases = [`50
6
put a 10
put b 20
get a
get a
get b
put c 30`, `50
1
get file`
];// 生成隨機 300000 個 put/get 操作用例,文件名最多100個不重復,超過26個字母范圍用數字后綴
(function(){const ops = [];const fileNames = [];let totalFiles = 0;const maxFiles = 100;const maxFileSize = 100;const totalOps = 300000;const cacheSize = 1000;function getFileName(idx) {if (idx < 26) {return String.fromCharCode(97 + idx); // 'a' ~ 'z'} else {return String.fromCharCode(97 + (idx % 26)) + (Math.floor(idx / 26));}}for (let i = 0; i < totalOps; i++) {if (Math.random() < 0.5 || totalFiles === 0) {// put 操作let idx = Math.floor(Math.random() * maxFiles);let fileName = getFileName(idx);let fileSize = Math.floor(Math.random() * maxFileSize) + 1;ops.push(`put ${fileName} ${fileSize}`);if (!fileNames.includes(fileName)) {fileNames.push(fileName);totalFiles++;}} else {// get 操作let fileName = fileNames[Math.floor(Math.random() * fileNames.length)];ops.push(`get ${fileName}`);}}const input = `${cacheSize}\n${totalOps}\n${ops.join('\n')}`;cases.push(input);
})();let caseIndex = 0;
let lineIndex = 0;const readline = (function () {let lines = [];return function () {if (lineIndex === 0) {lines = cases[caseIndex].trim().split("\n").map((line) => line.trim());}return lines[lineIndex++];};
})();caseIndex = 0;
lineIndex = 0;
cases.forEach((_, i) => {caseIndex = i;lineIndex = 0;entry();console.log('-------');
});

驗證

兩種方法測試結果相同:
在這里插入圖片描述

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

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

相關文章

Python中的sys.path與PYTHONPATH全解析:模塊導入路徑的底層機制與最佳實踐

在Python項目開發中&#xff0c;很多人遇到過類似“模塊導入失敗”、“路徑找不到”、“相對導入與絕對導入混亂”等問題。而這些問題的根源&#xff0c;幾乎都繞不開一個核心概念——Python模塊搜索路徑。 今天&#xff0c;我們圍繞sys.path 和 PYTHONPATH環境變量&#xff0…

python:如何調節機器學習算法的魯棒性,以支持向量機SVM為例,讓伙伴們看的更明白

魯棒性&#xff08;Robustness&#xff09;指模型在噪聲數據或異常值干擾下保持性能穩定的能力。想詳細了解的可參考本人之前的博文 python機器學習&#xff1a;評價智能學習算法性能與效果的常見術語&#xff1a;不收斂、過擬合、欠擬合、泛化能力、魯棒性一句話、一張圖給您…

號源加鎖升級思路(解決高并發問題)

原先邏輯鏈接&#xff1a;號源預約加鎖思路_java 預約 接口加鎖-CSDN博客 一、進行治療項目和號源數據緩存 1.新建一個定時任務&#xff0c;主要在凌晨時緩存治療項目和號源數據 1.1.類中使用redission獲取鎖&#xff08;用于分布式系統獲取數據&#xff0c;保證原子性&…

MCP革命:AI世界的“USB-C”接口如何重塑智能體與外部工具的連接

> 一條標準化的數據通道,讓AI從“對話專家”蛻變為“行動專家”,背后是一場由協議驅動的工具連接革命。 2024年11月,Anthropic公司開源了**Model Context Protocol(MCP)**。在短短9個月內,這項技術徹底改變了AI與外部世界的交互方式。截至2025年8月,MCP服務數量**從…

啟用“安全登錄”組合鍵(Ctrl+Alt+Delete)解鎖

文章目錄背景目標功能操作步驟效果背景 在日常工作中&#xff0c;我們有時需要讓電腦長期開機運行&#xff08;如處理長任務、作為服務器等&#xff09;。然而&#xff0c;這其中存在一個潛在風險&#xff1a;當電腦處于鎖屏或登錄界面時&#xff0c;如果有人無意中觸碰鍵盤比…

【08】C++實戰篇——C++ 生成動態庫.dll 及 C++調用DLL,及實際項目中的使用技巧

文章目錄一、創建動態庫dll (方法一)1 生成C 動態庫dll1.1 創建項目MyDLL1.2 編寫.h 和 .cpp文件1.3 設置 及 生成 DLL2 調用 C 動態庫dll2.1 創建C 空項目DLLtest2.2 動態庫配置 及代碼調用測試3 實際項目中的使用技巧3.1 設置dll輸出路徑3.2 設置頭文件引入路徑3.3 改進后 測…

kettle插件-kettle http client plus插件,輕松解決https接口無法調用文件流下載問題

場景&#xff1a;小伙伴在使用kettle調用https接口過程中無法正常調用&#xff0c;程序出錯問題&#xff0c;今天演示下用自研插件輕松解決這個問題。1、使用openssl 生成自簽名證書openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 3652、使用…

C#中的除法

在C#中&#xff0c;除法操作可以通過使用 / 運算符執行。這個運算符可以進行整數除法或浮點除法&#xff0c;這取決于操作數的類型。整數除法當兩個整數相除時&#xff0c;結果將自動向下取整到最接近的整數。這意味著結果是一個整數&#xff0c;而不是小數。int a 10; int b …

PPT文件密碼解密工具推薦:Tenorshare PassFab for PPT綠色免安裝一鍵解除密碼限制,附詳細教程和下載地址

前段時間&#xff0c;我幫朋友做一個商業演示的 PPT&#xff0c;為了防止文件被誤操作或者內容泄露&#xff0c;我給 PPT 設置了密碼。結果等朋友來拿文件的時候&#xff0c;我居然把密碼忘得干干凈凈&#xff0c;這下可把我倆都急壞了。朋友那邊馬上就要用這個 PPT 去參加重要…

【數據結構】二叉樹接口實現指南:遞歸方法的高效運用 (附經典算法OJ)

文章目錄 1、前置說明 1、定義二叉樹結點結構 2、創建新節點 3、手動創建二叉樹 2、二叉樹的遍歷 1、前序&#xff0c;中序和后序遍歷 1.1、二叉樹前序遍歷 1.2、二叉樹中序遍歷 1.3、二叉樹后序遍歷 2、二叉樹層序遍歷 3、二叉樹的基礎操作 1、二叉樹節點總數 2、…

自動駕駛控制算法——LQR控制算法

自動駕駛控制算法——LQR控制算法 文章目錄自動駕駛控制算法——LQR控制算法**一、LQR 是什么&#xff1f;**二、LQR 原理2.1 線性狀態空間模型 (State–Space Model)2.2 二次型性能指標 JJJ2.3 代數黎卡提方程 (ARE)2.4 特點總結2.5 一句話總結 LQR 原理&#xff1a;2.5.1 場景…

Jotai:React輕量級原子化狀態管理,告別重渲染困擾

簡介 Jotai 是一個為 React 提供的原子化狀態管理庫&#xff0c;采用自下而上的方法來進行狀態管理。Jotai 受 Recoil 啟發&#xff0c;通過組合原子來構建狀態&#xff0c;并且渲染基于原子依賴性進行優化。這解決了 React 上下文的額外重新渲染問題&#xff0c;并消除了對 m…

C語言數據結構(7)貪吃蛇項目2.貪吃蛇項目實現

8. 核心邏輯實現分析 8.1 游戲主邏輯 程序開始就設置程序支持本地模式&#xff0c;然后進入程序的主邏輯。 主邏輯分為3個過程&#xff1a; ? 游戲開始&#xff08;GameStart&#xff09;完成游戲的初始化。 ? 游戲運行&#xff08;GameRun&#xff09;完成游戲運行邏輯的…

知識蒸餾 - 最小化KL散度與最小化交叉熵是完全等價的

知識蒸餾 - 最小化KL散度與最小化交叉熵是完全等價的 flyfish KL散度與交叉熵的數學關系 對于兩個概率分布 PPP&#xff08;真實分布&#xff09;和 QQQ&#xff08;模型預測分布&#xff09;&#xff0c;KL散度的定義是&#xff1a; DKL(P∥Q)∑xP(x)log?(P(x)Q(x)) D_{KL}(P…

設計心得——網絡包的處理

一、介紹 在程序的開發中&#xff0c;網絡開發是一個重要的應用場景。畢竟這些年IT行業之所以火&#xff0c;主要還是互聯網&#xff08;移動互聯網&#xff09;帶來的。網絡開發&#xff0c;有各種平臺、框架以及系統和庫提供的API&#xff0c;如果說網絡開發是一個特別復雜和…

sqli-labs通關筆記-第30關GET字符注入(WAF繞過 雙引號閉合 手工注入+腳本注入兩種方法)

目錄 一、源碼分析 1、index.php代碼審計 2、login.php代碼審計 3、java_implimentation函數 4、whitelist函數 5、SQL安全性分析 二、滲透實戰 1、進入靶場 2、WAF探測 &#xff08;1&#xff09;觸發WAF &#xff08;2&#xff09;繞過WAF 3、手工注入 &#xf…

【openlayers框架學習】九:openlayers中的交互類(select和draw)

文章目錄openlayers進階28 openlayers中的事件29 openlayers中select交互類的使用30 openlayers中select常見的配置選項31 openlayers中繪制交互類&#xff08;Draw&#xff09;openlayers進階 28 openlayers中的事件 常用進行事件交互的對象&#xff1a;map\view\source29 o…

Java企業級應用性能優化實戰

在企業級Java應用開發中,性能優化是確保系統穩定運行的關鍵因素。本文將從多個維度深入分析Java應用性能瓶頸,并提供實戰優化方案。 ?? 性能優化核心領域 1. 對象操作性能優化 在企業應用中,對象拷貝是一個高頻操作,特別是在分層架構中的DO、DTO、VO轉換。選擇合適的拷…

LLM Prompt與開源模型資源(3)如何寫一個好的 Prompt

學習材料&#xff1a;https://www.hiascend.com/developer/courses/detail/1935520434893606913 &#xff08;3.5&#xff09;學習時長&#xff1a; 預計 60 分鐘學習目的&#xff1a; 了解提示工程的定義與作用熟悉提示工程的關鍵技術相關概念掌握基于昇騰適配的大模型提示工程…

日志管理工具 ——ELK Stack

一、ELK Stack 概述1.1 核心組件ELK Stack&#xff08;現更名為 Elastic Stack&#xff09;是一套開源的日志收集、存儲、分析和可視化平臺&#xff0c;由三個核心組件構成&#xff1a;Elasticsearch&#xff1a;分布式搜索引擎&#xff0c;負責日志數據的存儲、索引和快速查詢…