【AI插件開發】Notepad++ AI插件開發實踐:支持配置界面

一、引用

此前的系列文章已基本完成了Notepad++的AI插件的功能開發,但是此前使用的配置為JSON配置文件,不支持界面配置。

本章在此基礎上集成支持配置界面,這樣不需要手工修改配置文件,直接在界面上操作,方便快捷。

:項目已開源、鏡像,歡迎StartFork使用和指正。

二、配置界面設計

在插件的菜單欄中支持參數配置,用戶點擊該菜單時彈出配置對話框,在該配置界面對配置進行增刪改查。

{"platform": "infini","timeout": 90,"platforms": {"infini": {"enable_ssl": true,"base_url": "cloud.infini-ai.com","authorization": {"type": "Bearer","data": "sk-xxx"},"model_name": "deepseek-r1-distill-qwen-32b","models": [ "deepseek-r1-distill-qwen-32b", "deepseek-r1", "deepseek-v3" ],"generate_endpoint": {"method": "post","api": "/maas/v1/completions","prompt": ""},"chat_endpoint": {"method": "post","api": "/maas/v1/chat/completions","prompt": ""},"models_endpoint": {}}}
}

根據現有的配置文件格式,對配置界面分為兩塊區域,區域一配置插件相關的參數,區域二設計一個AI平臺的下拉列表框,支持AI平臺相關的參數。

考慮到AI平臺有多個接口(雖然現在只用了對話接口),因此接口部分使用表單,但表單不方便修改,因此需要新增一個字段編輯對話框,雙擊列表行時支持編輯列表行。

這樣,界面設計差不多這樣了。因為使用原生的Windows編程,因此需要花費較多的時間處理界面、事件,對Windows接口也是半生不熟,一邊做一邊查,所以還是比較費時間的,整體功能流程如下:

選擇平臺
添加/刪除模型
修改接口參數
確認保存
取消
用戶點擊參數配置菜單
彈出配置對話框
初始化控件/加載配置
用戶操作
加載平臺配置
更新模型列表
打開字段編輯對話框
保存字段修改
寫入配置文件
關閉對話框
流程結束

先看下效果圖:
配置界面

三、參數配置界面

1. 創建對話框資源

  • 先在插件的資源文件中新建一個ID為IDD_DIALOG_PLUG_CONFIG的對話框,設計菜單界面,如下:
    在這里插入圖片描述

2. 新建一個類,關聯該對話框資源

PluginConfigDlg::PluginConfigDlg(HINSTANCE hInstance, Scintilla::PluginConfig& plugConf) : m_hInstance(hInstance), m_plugConfig(plugConf)
{// 創建無模式對話框m_hDlg = CreateDialogParam(m_hInstance,MAKEINTRESOURCE(IDD_DIALOG_PLUG_CONFIG),nullptr,DlgProc,reinterpret_cast<LPARAM>(this));if (m_hDlg) {InitControls();LoadConfig();}
}

在構造函數中創建對話框,關聯對話框資源ID,并指定消息處理函數為DlgProc

INT_PTR CALLBACK PluginConfigDlg::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {if (uMsg == WM_INITDIALOG) {// 關聯類實例指針到窗口SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);}// 獲取類實例指針PluginConfigDlg* pThis = reinterpret_cast<PluginConfigDlg*>(GetWindowLongPtr(hDlg, GWLP_USERDATA));if (pThis) {return pThis->RealDlgProc(hDlg, uMsg, wParam, lParam);}return FALSE;
}

DlgProc中處理WM_INITDIALOG消息,關聯類實例指針到窗口,并將事件透傳到類的實際消息處理函數RealDlgProcRealDlgProc可以便捷地訪問操作類對象成員變量及函數。

3. 初始化界面

因為界面部分控件是下拉組合框和列表,因此需先初始化該部分,主要是初始化下拉列表數據、表單頭,方便后續直接使用:

void PluginConfigDlg::InitControls() 
{// 授權類型HWND hWnd = GetDlgItem(m_hDlg, IDC_COMBO_AUTH_TYPE);SendMessage(hWnd, CB_RESETCONTENT, 0, 0);SendMessageW(hWnd, CB_ADDSTRING, 0, (LPARAM)L"無");SendMessageW(hWnd, CB_ADDSTRING, 0, (LPARAM)L"Basic");SendMessageW(hWnd, CB_ADDSTRING, 0, (LPARAM)L"Bearer");SendMessageW(hWnd, CB_ADDSTRING, 0, (LPARAM)L"ApiKey");// 接口列表HWND hList = GetDlgItem(m_hDlg, IDC_LIST_ENDPOINT);// 1. 設置基礎樣式(必須包含 LVS_REPORT)SetWindowLongW(hList, GWL_STYLE, GetWindowLongW(hList, GWL_STYLE) | LVS_REPORT |      // 報表視圖LVS_SINGLESEL     // 禁止多選);// 2. 配置擴展樣式ListView_SetExtendedListViewStyle(hList, LVS_EX_GRIDLINES |    // 顯示網格線LVS_EX_FULLROWSELECT  // 整行選中);// 3. 初始化列頭LVCOLUMNW lvc = {0};lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;// 批量添加列const struct {int width;const wchar_t* title;} columns[] = {{50, L"名稱"},{50, L"方法"},{300, L"接口"},{150, L"參數"}};for (size_t i = 0; i < _countof(columns); ++i) {lvc.fmt = LVCFMT_CENTER;lvc.cx = columns[i].width;lvc.pszText = const_cast<LPWSTR>(columns[i].title);ListView_InsertColumn(hList, i, &lvc);}
}

然后是將配置文件中的內容在界面上顯示,設置超時、設置當前平臺:

bool PluginConfigDlg::LoadConfig()
{SetDlgItemTextA(m_hDlg, IDC_EDIT_TIMEOUT, std::to_string(m_plugConfig.timeout).c_str());int nSel = 0;HWND hWnd = GetDlgItem(m_hDlg, IDC_COMBO_PLATFORM);SendMessage(hWnd, CB_RESETCONTENT, 0, 0);int nIdx = 0;for (auto& p : m_plugConfig.platforms){SendMessageA(hWnd, CB_ADDSTRING, 0, (LPARAM)p.first.c_str());if (!Scintilla::String::icasecompare(p.first, m_plugConfig.platform)){nSel = nIdx;}nIdx++;}SendMessage(hWnd, CB_SETCURSEL, (WPARAM)nSel, 0);auto& platform = m_plugConfig.Platform();Load(platform);return true;
}

其中平臺配置信息只顯示單個,即當前選中的平臺,啟動時顯示當前配置的平臺信息,然后調用Load函數加載該平臺信息配置。考慮到配置需要支持增刪改查,因此通過平臺組合框下拉列表可以切換到不同平臺:

void PluginConfigDlg::Load(const Scintilla::PlatformConfig& platform)
{// SSLCheckDlgButton(m_hDlg, IDC_CHECK_SSL, platform.enable_ssl ? BST_CHECKED : BST_UNCHECKED);// 授權類型HWND hWnd = GetDlgItem(m_hDlg, IDC_COMBO_AUTH_TYPE);SendMessage(hWnd, CB_SETCURSEL, (WPARAM)(int)platform.authorization.eAuthType, 0);// 授權數據SetDlgItemTextA(m_hDlg, IDC_EDIT_AUTH_DATA, platform.authorization.auth_data.c_str());// 根地址SetDlgItemTextA(m_hDlg, IDC_EDIT_ROOT_URL, platform.base_url.c_str());// 模型名稱int nSel = 0;int nIdx = 0;hWnd = GetDlgItem(m_hDlg, IDC_COMBO_MODEL_NAME);SendMessage(hWnd, CB_RESETCONTENT, 0, 0);for (auto& m : platform.models){SendMessageA(hWnd, CB_ADDSTRING, 0, (LPARAM)m.c_str());if (m == platform.model_name){nSel = nIdx;}nIdx++;}SendMessage(hWnd, CB_SETCURSEL, (WPARAM)nSel, 0);hWnd = GetDlgItem(m_hDlg, IDC_LIST_ENDPOINT);ListView_DeleteAllItems(hWnd);if (!platform.base_url.empty()){auto pE = &platform.chat_endpoint;ListViewAddRow(hWnd, { "對話", pE->method, pE->api, pE->prompt});pE = &platform.generate_endpoint;ListViewAddRow(hWnd, { "生成", pE->method, pE->api, pE->prompt});pE = &platform.models_endpoint;ListViewAddRow(hWnd, { "模型", pE->method, pE->api, pE->prompt});}
}

4. 切換平臺

處理平臺切換事件,并顯示切換后平臺信息

#define OnDlgItemEvent(nItemId, nEventId, fnCall) if(LOWORD(wParam) == nItemId && HIWORD(wParam) == nEventId) { fnCall(); return TRUE; }
INT_PTR PluginConfigDlg::RealDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{switch (uMsg) {case WM_CLOSE:DestroyWindow(m_hDlg);return TRUE;case WM_INITDIALOG:return TRUE;case WM_COMMAND:{OnDlgItemEvent(IDC_COMBO_PLATFORM, CBN_SELCHANGE, OnPlatformChange);OnDlgItemEvent(IDC_COMBO_MODEL_NAME, CBN_SELCHANGE, OnModelChange);OnDlgItemEvent(IDC_BUTTON_MODEL_SAVE, BN_CLICKED, OnSaveMode);OnDlgItemEvent(IDC_BUTTON_MODEL_DEL, BN_CLICKED, OnRemoveModel);OnDlgItemEvent(IDC_BUTTON_PLATFORM_SAVE, BN_CLICKED, OnSavePlatform);OnDlgItemEvent(IDC_BUTTON_PLATFORM_DEL, BN_CLICKED, OnRemovePlatform);OnDlgItemEvent(IDCANCEL, BN_CLICKED, LoadConfig);OnDlgItemEvent(IDOK, BN_CLICKED, SaveConfig);}break;case WM_NOTIFY:LPNMITEMACTIVATE pNmItem = (LPNMITEMACTIVATE)lParam;if (pNmItem->hdr.idFrom == IDC_LIST_ENDPOINT &&  pNmItem->hdr.code == NM_DBLCLK) {OnEndpointListViewDBClick(pNmItem);return TRUE;}break;}return FALSE;
}

在窗口事件處理函數中,處理WM_COMMAND消息,根據消息參數識別出控件對象和消息類型,處理平臺切換是OnDlgItemEvent(IDC_COMBO_PLATFORM, CBN_SELCHANGE, OnPlatformChange),實現內容在函數OnPlatformChange中:

void PluginConfigDlg::OnPlatformChange()
{std::string name;if (!GetComboSelectedText(GetDlgItem(m_hDlg, IDC_COMBO_PLATFORM), name) || name.empty()){return;}auto e = m_plugConfig.platforms.find(name);if (e == m_plugConfig.platforms.end()){return;}Load(e->second);
}

獲取ComboBox的當前選中項,注意:不能取當前控件的文本即GetWindowText,否則取到的是選中前的內容。然后調用Load函數加載切換后的AI平臺配置信息。

5. 模型刪除

void PluginConfigDlg::OnRemoveModel()
{HWND hCombo = GetDlgItem(m_hDlg, IDC_COMBO_MODEL_NAME);if (hCombo == nullptr){return;}auto name = String::Trim(GetComboSelectedText(IDC_COMBO_MODEL_NAME));if (name.empty()){ShowConfigError("請輸入或選擇當前模型名稱");return;}auto nRet = ShowMsgBox(String::Format("是否要刪除模型【%s】配置?", name.c_str()), "刪除確認", MB_YESNO | MB_ICONQUESTION);if (nRet != IDYES){return;}SendMessageA(hCombo, CB_DELETESTRING, 0, (LPARAM)name.c_str());
}

刪除當前選中項的模型名稱,僅是從列表中刪除,不是從對象的內存中刪除,后續通過保存平臺配置時更新刪除后的列表。

6. 模型添加

void PluginConfigDlg::OnSaveMode()
{HWND hCombo = GetDlgItem(m_hDlg, IDC_COMBO_MODEL_NAME);if (hCombo == nullptr){return;}auto name = String::Trim(GetComboSelectedText(IDC_COMBO_MODEL_NAME));if (name.empty()){ShowConfigError("請輸入或選擇當前模型名稱");return;}SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)name.c_str());
}

刪除當前選中項的模型名稱,和刪除類似,僅是從列表中刪除。

7.刪除平臺配置

void PluginConfigDlg::OnRemovePlatform()
{HWND hPlatform = GetDlgItem(m_hDlg, IDC_COMBO_PLATFORM);if (hPlatform == nullptr){return;}std::string name;auto pPlat = GetCurSelPlatform(name);if (!pPlat){ShowConfigError("請選擇當前平臺名稱");return;}auto nRet = ShowMsgBox(String::Format("是否要刪除平臺【%s】配置?", name.c_str()), "刪除確認", MB_YESNO | MB_ICONQUESTION);if (nRet != IDYES){return;}SendMessageA(hPlatform, CB_DELETESTRING, 0, (LPARAM)name.c_str());m_plugConfig.platforms.erase(name);// 清空數據Load(PlatformConfig());
}

獲取當前選中的平臺配置,然后從列表和內存中刪除該平臺配置,刪除后清空平臺配置信息(通過加載一個空對象實現),此外為防止誤刪,刪除前做了彈框確認。

8.修改或新增平臺配置

bool PluginConfigDlg::OnSavePlatform()
{HWND hPlatform = GetDlgItem(m_hDlg, IDC_COMBO_PLATFORM);if (hPlatform == nullptr){return false;}std::string name;auto pPlat = GetCurSelPlatform(name);if (name.empty()){ShowConfigError("請輸入或選擇當前平臺名稱");return false;}Scintilla::PlatformConfig plat;if (!Save(plat)){return false;}if (pPlat == nullptr){// 新增SendMessageA(hPlatform, CB_ADDSTRING, 0, (LPARAM)name.c_str());m_plugConfig.platforms[name] = plat;}else{*pPlat = plat;}m_plugConfig.Save("");return true;
}

先把界面上平臺信息配置保存到一個臨時變量中(防止保存了部分就返回),然后根據是否已存在該名稱的平臺配置決定是新增還是更新信息。

9. 響應接口列表行雙擊事件

INT_PTR PluginConfigDlg::RealDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{switch (uMsg) {case WM_NOTIFY:LPNMITEMACTIVATE pNmItem = (LPNMITEMACTIVATE)lParam;if (pNmItem->hdr.idFrom == IDC_LIST_ENDPOINT &&  pNmItem->hdr.code == NM_DBLCLK) {OnEndpointListViewDBClick(pNmItem);return TRUE;}break;}return FALSE;
}

處理窗口的WM_NOTIFY消息,然后根據控件ID和事件類型識別出是列表雙擊事件,然后列表雙擊編輯函數OnEndpointListViewDBClick

四、字段編輯界面

字段編輯框設計為一個通用的編輯窗口,提供一個字段組合,然后界面顯示并支持編輯字段信息。
步驟也是和創建配置對話框差不多,不過這里創建的是一個模態對話框,不使用Show顯示,而是使用DoModal模態對話框顯示。

1. 調用編輯窗口更新字段

void PluginConfigDlg::OnEndpointListViewDBClick(LPNMITEMACTIVATE& pNmItem)
{if (pNmItem == nullptr){return;}int nRow = pNmItem->iItem;if (nRow < 0){return;}std::map<std::string, std::string> fields;if (ListViewGetRow(GetDlgItem(m_hDlg, IDC_LIST_ENDPOINT), nRow, fields) <= 0){return;}FieldEditDlg dlg(m_hInstance, m_hDlg);for (auto& [k, v] : fields){dlg.m_mapField[k] = { v };}dlg.m_mapField["方法"].options = { "post", "get" };dlg.m_mapField["方法"].type = FieldEditDlg::FieldType::Combo;dlg.m_strTitle = "接口參數設置";dlg.m_nLabelWidth = 40;if (dlg.DoModal() != IDOK){return;}std::vector<std::string> vs;std::vector<std::string> names = { "名稱", "方法", "接口", "參數" };for (auto& name : names){auto e = dlg.m_mapField.find(name);if (e == dlg.m_mapField.end()){return;}vs.push_back(e->second.val);}ListViewSetRow(GetDlgItem(m_hDlg, IDC_LIST_ENDPOINT), nRow, vs);
}

這里使用map存儲字段,感覺使用vector更合適,有序且字段存取方便,后續改一下。

2. 創建模態編輯窗口

#pragma once
#include <windows.h>
#include "PluginConf.h"
#include <commctrl.h>namespace Ui
{class Util{public:// 局長顯示窗口static void Show(HWND hWnd, bool bShow, HWND hParent = nullptr);static std::string GetText(HWND hWnd);};
}class FieldEditDlg
{
public:enum class FieldType{Edit,Combo,};struct Field{std::string val;std::vector<std::string> options;FieldType type = FieldType::Edit;bool readonly = false;};FieldEditDlg(HINSTANCE hInstance, HWND hParent);~FieldEditDlg();static INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);INT_PTR DoModal();private:INT_PTR RealDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);void CreateDynamicControls();void OnInitDialog();void OnSave();public:std::map<std::string, Field> m_mapField;int m_nLabelWidth = 100;int m_nBoxWidth = 300;std::string m_strTitle = "字段設置";private:HINSTANCE m_hInstance = nullptr;HWND m_hDlg = nullptr;HWND m_hParent = nullptr;HFONT m_hFont = nullptr;std::map<HWND, std::string> m_hwndMap;
};

注意,這里不在構造函數中初始化創建窗口,而是在DoModal中創建,并等待窗口結束:

INT_PTR FieldEditDlg::DoModal()
{// 創建模態對話框(需提前定義對話框模板ID,假設為IDD_FIELD_EDIT_DLG)return DialogBoxParam(m_hInstance, MAKEINTRESOURCE(IDD_DIALOG_EDIT_FIELD),m_hParent,FieldEditDlg::DlgProc,reinterpret_cast<LPARAM>(this));
}// 對話框消息處理
INT_PTR CALLBACK FieldEditDlg::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{if (uMsg == WM_INITDIALOG) {// 關聯類實例指針到窗口SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);auto* pThis = reinterpret_cast<FieldEditDlg*>(lParam);pThis->m_hDlg = hDlg;pThis->OnInitDialog();Ui::Util::Show(hDlg, true);return TRUE;}// 獲取類實例指針auto pThis = reinterpret_cast<FieldEditDlg*>(GetWindowLongPtr(hDlg, GWLP_USERDATA));if (pThis) {return pThis->RealDlgProc(hDlg, uMsg, wParam, lParam);}return FALSE;
}INT_PTR FieldEditDlg::RealDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{switch (uMsg) {case WM_INITDIALOG: {SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)this);OnInitDialog();return TRUE;}case WM_COMMAND: {int wmId = LOWORD(wParam);int wmEvent = HIWORD(wParam);if (wmId == IDOK && wmEvent == BN_CLICKED) {OnSave();EndDialog(m_hDlg, IDOK);return TRUE;} else if (wmId == IDCANCEL && wmEvent == BN_CLICKED) {EndDialog(m_hDlg, IDCANCEL);return TRUE;}break;}case WM_CLOSE:EndDialog(m_hDlg, IDCLOSE);return TRUE;}return FALSE;
}void FieldEditDlg::OnInitDialog()
{if(!m_mapField.empty()) CreateDynamicControls();SetWindowTextA(m_hDlg, m_strTitle.c_str());
}

3. 更新保存數據

void FieldEditDlg::OnSave()
{for (auto& [k, v] : m_hwndMap){m_mapField[v].val = Ui::Util::GetText(k);}
}

5. 總結說明

這一篇文章主要介紹了關于配置的兩個對話框的實現,完成了手工編輯JSON配置文件到界面快捷配置的革命轉換,本文主要涉及的技術要點如下:

核心架構設計
對話框資源系統
配置數據管理
動態控件引擎
事件處理中樞
Windows API創建對話框
類實例與窗口綁定
消息循環處理
JSON結構內存映射
平臺配置對象樹
雙向數據同步機制
智能列表視圖
動態組合框
多態控件渲染
WM_COMMAND處理
WM_NOTIFY響應
異步操作隊列
關鍵技術實現
核心創新點
原生窗口性能優化
多層級配置繼承
零拷貝數據交換
字段類型自適配
B1,B2,B3

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

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

相關文章

Android12 ServiceManager::addService源碼解讀

源碼 Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {auto ctx mAccess->getCallingContext();// apps cannot add servicesif (multiuser_get_app_id(ctx.uid) >…

第十四節:實戰場景-何實現全局狀態管理?

React.createElement調用示例 Babel插件對JSX的轉換邏輯 React 全局狀態管理實戰與 JSX 轉換原理深度解析 一、React 全局狀態管理實現方案 1. Context API useReducer 方案&#xff08;輕量級首選&#xff09; // 創建全局 Context 對象 const GlobalContext createConte…

第四十八篇 電信行業數倉建設實戰指南:從架構設計到場景落地

目錄 一、云原生架構設計實戰1.1 計算存儲分離架構搭建1.2 實時離線融合方案 二、維度建模深度解析2.1 電信業務建模方法論2.2 典型模型設計示例 三、ETL流程優化實踐3.1 增量同步技術選型3.2 數據清洗規范 四、核心場景實現方案4.1 用戶流失預警模型 五、數據治理實施指南5.1 …

2025年山東燃氣瓶裝送氣工考試真題練習

燃氣瓶裝送氣工考試真題練習 單選題 1、液化石油氣主要成分是&#xff08; &#xff09;。 A. 甲烷 B. 丙烷、丁烷 C. 一氧化碳和氫氣 答案&#xff1a;B 2、燃氣鋼瓶搬運過程中&#xff0c;正確的做法是&#xff08; &#xff09;。 A. 滾動鋼瓶 B. 踢鋼瓶 C. 輕拿輕…

《AI大模型應知應會100篇》第24篇:限定輸出格式:如何讓AI回答更加結構化

第24篇&#xff1a;限定輸出格式&#xff1a;如何讓AI回答更加結構化 摘要 在日常使用AI的過程中&#xff0c;我們經常希望得到的不僅僅是“正確”的答案&#xff0c;更是一個清晰、規范、易于處理的回答。無論是生成數據分析報告、代碼片段&#xff0c;還是教學內容&#xff…

【MySQL】數據庫和表的操作詳解

目錄 一、數據庫&#xff1a; 1、查看數據庫&#xff1a; 2、創建數據庫&#xff1a; 3、刪除數據庫&#xff1a; 4、數據庫的編碼問題&#xff1a; 5、校驗規則對數據庫的影響&#xff1a; 6、修改數據庫&#xff1a; 7、庫的備份與恢復&#xff1a; 8、查看鏈接情況…

Docker--Docker鏡像原理

docker 是操作系統層的虛擬化&#xff0c;所以 docker 鏡像的本質是在模擬操作系統。 聯合文件系統&#xff08;UnionFS&#xff09; 聯合文件系統&#xff08;UnionFS&#xff09; 是Docker鏡像實現分層存儲的核心技術&#xff0c;它通過將多個只讀層&#xff08;Image Laye…

雙層Key緩存

雙層 Key 緩存是一種針對 緩存擊穿 和 雪崩問題 的優化方案&#xff0c;其核心思想是通過 主備雙緩存 的機制&#xff0c;確保在熱點數據過期時仍能提供可用服務&#xff0c;同時降低對數據庫的瞬時壓力。以下是其核心原理、實現細節及適用場景的深度解析&#xff1a; 一、核心…

力扣每日打卡 2176. 統計數組中相等且可以被整除的數對(簡單)

力扣 2176. 統計數組中相等且可以被整除的數對 簡單 前言一、題目內容二、解題方法1. 暴力解法2.官方題解官方也是暴力解法 前言 這是刷算法題的第十三天&#xff0c;用到的語言是JS 題目&#xff1a;力扣 2176. 統計數組中相等且可以被整除的數對(簡單) 一、題目內容 給你一…

云服務器和物理服務器

服務器&#xff0c;作為互聯網世界中數據存儲與處理的關鍵樞紐&#xff0c;其重要性不言而喻。在眾多服務器類型中&#xff0c;云服務器和物理服務器占據了主導地位&#xff0c;它們各自有著獨特的特點和應用場景。咱們就來深入探討一下這兩者的區別。

Kubernetes Pod 調度策略:從基礎到進階

文章目錄 環境Kubernetes 部署Kubernetes Pod 調度策略Kubernetes Pod 調度策略對照表調度流程經歷階段案例展示生成yaml文件默認調度節點選擇器為節點添加標簽編寫 Deployment 配置文件應用資源并查看調度結果 Node Affinity&#xff08;節點親和性&#xff09;為節點添加標簽…

SQLite、MySQL、SQL Server、Oracle 和 PostgreSQL 五種數據庫的區別

以下是 SQLite、MySQL、SQL Server、Oracle 和 PostgreSQL 五種主流關系型數據庫管理系統(RDBMS)的區別,從多個維度進行對比: 1. 架構與部署 SQLite(Structured Query Language Lite?): 嵌入式數據庫,無服務器架構。數據庫存儲在一個單一的磁盤文件中。部署簡單,適合輕量…

電路安全智控系統與主機安全防護系統主要功能是什么

電路安全智控系統被稱為電路安全用電控制系統。電路安全智控系統具備一系列強大且實用的功能。電路安全智控系統能夠對總電壓、總電流、總功率、總電能&#xff0c;以及各分路的電壓、電流、功率、電能和功率因素等進行全方位的監控。在大型工廠的電力分配中&#xff0c;通過對…

使用Lean 4和C#進行數學定理證明與邏輯推理

步驟1&#xff1a;安裝與配置環境 安裝Lean 4 訪問Lean官網或GitHub倉庫&#xff0c;按照指南安裝Lean 4及配套工具鏈&#xff08;如VS Code擴展&#xff09;。 設置C#開發環境 安裝.NET SDK及IDE&#xff08;如Visual Studio或Rider&#xff09;&#xff0c;確保C#開發環境正…

八股文---MySQl(3)

目錄 12.事務的特性是什么&#xff1f;可以詳細說一下嗎&#xff1f; 回答 13并發事務帶來哪些問題&#xff1f;怎么解決這些問題呢&#xff1f;MySQL的默認隔離級別是&#xff1f; 臟讀&#xff1a;一個事務讀到另外一個事務還沒有提交的數據。 不可重復讀&#xff1a;一個…

實驗五 內存管理實驗

實驗五 內存管理實驗 一、實驗目的 1、了解操作系統動態分區存儲管理過程和方法。 2、掌握動態分區存儲管理的主要數據結構--空閑表區。 3、加深理解動態分區存儲管理中內存的分配和回收。 4、掌握空閑區表中空閑區3種不同放置策略的基本思想和實現過程。 5、通過模擬程…

【MySQL】MySQL表的增刪改查(CRUD) —— 上篇

目錄 MySQL表的增刪改查&#xff08;CRUD&#xff09; 1. 新增&#xff08;Create&#xff09;/插入數據 1.1 單行數據 全列插入 insert into 表名 values(值, 值......); 1.2 單行數據 指定列插入 1.3 多行數據 指定列插入 1.4 關于時間日期&#xff08;datetime&am…

【MATLAB代碼例程】AOA與TOA結合的高精度平面地位,適用于四個基站的情況,附完整的代碼

本代碼實現了一種基于到達角(AOA) 和到達時間(TOA) 的混合定位算法,適用于二維平面內移動或靜止目標的定位。通過4個基站的協同測量,結合最小二乘法和幾何解算,能夠有效估計目標位置,并支持噪聲模擬、誤差分析和可視化輸出。適用于室內定位、無人機導航、工業監測等場景…

ModbusTCP 轉 Profinet 主站網關

一、 功能概述 1.1 設備簡介 本產品是 ModbusTCP 和 Profinet(M) 網關&#xff08;以下簡稱網關&#xff09;&#xff0c;使用數據映射 方式工作。 本產品在 ModbusTCP 側作為 ModbusTCP 從站&#xff0c;接 PLC 、上位機、 wincc 屏 等&#xff1b;在 Profin…

《AI大模型應知應會100篇》第25篇:Few-shot與Zero-shot使用方法對比

第25篇&#xff1a;Few-shot與Zero-shot使用方法對比 摘要 在大語言模型的應用中&#xff0c;**Few-shot&#xff08;少樣本&#xff09;和Zero-shot&#xff08;零樣本&#xff09;**是兩種核心的提示策略。它們各自適用于不同的場景&#xff0c;能夠幫助用戶在不進行額外訓練…