【汽車標定數據】動態優先級線程池在異步多文件解析中的應用

目錄

一、需求背景

項目背景:電控數據管理系統優化

優化方案:引入OLAP數據庫和動態線程池

線程池性能急需解決的問題

資源過載與閑置的平衡:

優先級處理與公平性:

任務類型適配性:

二、線程池介紹

2.1、線程池的核心設計分析

1. 頂層接口:Executor(任務提交與執行解耦)

2. 擴展接口:ExecutorService(增強任務管理和控制能力)

3. 抽象類:AbstractExecutorService(串聯任務執行流程)

4. 具體實現類:ThreadPoolExecutor(線程與任務協同管理)

2.2 線程池的執行流程

2.3 線程池中需要關注的幾個點

2.3.1 線程池狀態維護設計

1.?ctl變量的作用

2.?位運算的原理

3.?關鍵計算方法

2.3.2 線程池中的參數可以動態修改嗎

2.3.3 核心線程數可以單獨進行設置嗎

2.3.4? 隊列的數量怎么設置

2.3.4 線程池被創建后沒有任務過來,里面是不會有線程的,如何預熱。

2.3.4.1 全部啟動

2.3.4.2 只啟動一個

三、代碼實現

3.1 監聽naocs的配置中心,如果有變化更新參數

3.2 構建優先級枚舉類及其注冊分級線程池

3.2 構建線程池管理類和可調整隊列

3.2 構建具體任務類 和 場景策略枚舉調用


一、需求背景

項目背景:電控數據管理系統優化

電控數據管理系統主要用于處理汽車電子控制單元(ECU)的相關數據文件,包括解析、比對、合成和校驗等功能。核心文件包括:

  • A2L文件:大小約10~20MB,每個文件包含約8000個變量(如傳感器參數)。
  • Hex/S19文件:大小4~10MB,存儲ECU所有變量的地址和值(如內存映射數據)。
  • DCM文件:大小約1MB,包含1~5000個變量(具體數量取決于主機廠的管理規則)。

系統需要執行以下關鍵操作:

  1. 文件解析:將文件內容解析為可處理的數據結構(如變量列表)。
  2. 參數比對:比較不同文件中的上萬個參數,涉及單值、數組和MAP類型(例如,檢查A2L和Hex文件中的變量是否一致)。
  3. 文件合成:合并多個文件(如基于比對結果生成新文件),涉及上萬文件的處理。
  4. 文件校驗:驗證數據完整性(如檢查文件是否損壞或篡改)。
  5. 數據入庫:將解析結果存儲到數據庫,供后續查詢和分析。
  6. 等其他耗時計算的操作

這些操作都是CPU密集型任務(需要大量計算),尤其在批量操作(如同時處理多個文件)或多用戶并發訪問時,負載急劇增加。例如:

  • 單個文件解析可能需要幾秒到幾分鐘,取決于文件大小和復雜度。
  • 當10個用戶同時上傳文件時,系統可能面臨數十個并發任務,導致響應延遲或資源爭用。

優化方案:引入OLAP數據庫和動態線程池

為解決性能瓶頸,引入兩項技術:

  1. OLAP數據庫(Doris):項目中用到了大量的分析功能,需要設計海量數據的處理分析。Doris支持列式存儲和實時分析用于高效存儲和查詢海量數據,能加速數據入庫和比對操作(例如,查詢變量值時,響應時間從秒級降到毫秒級)。
  2. 動態優先級線程池:用于管理任務執行線程,根據系統負載自動調整資源。線程池的核心是動態分配線程數,優先處理高優先級任務(如用戶實時請求),避免低優先級任務(如后臺批量處理)阻塞系統。

線程池性能急需解決的問題

動態線程池能顯著提升系統性能,但必須解決以下關鍵問題,否則在高負載下可能導致系統崩潰或效率低下:

  1. 資源過載與閑置的平衡

    • 問題:在用戶量激增時(如多用戶批量上傳文件),線程數不足會導致任務排隊,響應時間變慢(例如,解析延遲從1秒增至10秒)。反之,線程過多會耗盡CPU,引發系統卡頓。
    • 急需解決:線程池必須根據解析時間(任務耗時)和用戶量(并發請求數)動態調整線程數。例如,當用戶量增加時,自動增加線程;當任務耗時較長時,減少線程以避免爭用。
  2. 優先級處理與公平性

    • 問題:不同任務優先級不同(如用戶交互操作優先于后臺合成),但靜態線程池可能讓低優先級任務“餓死”高優先級任務(例如,批量文件合成占用所有線程,導致用戶無法及時查看結果)。
    • 急需解決:線程池需支持動態優先級隊列。高優先級任務(如文件校驗)應優先獲取線程;低優先級任務(如批量入庫)在系統空閑時執行。這需要算法實時計算任務權重(如基于用戶等待時間或任務類型)。
  3. 任務類型適配性

    • 問題:文件解析任務差異大(如A2L文件解析比DCM更耗時),線程池若“一刀切”分配線程,會造成資源浪費(例如,簡單任務占用線程但快速完成,復雜任務等待)。
    • 急需解決:線程池應識別任務類型(如通過預估解析時間),并動態分配線程資源。例如,復雜任務(耗時>5秒)分配更多線程,簡單任務(耗時<1秒)合并處理。

二、線程池介紹

2.1、線程池的核心設計分析

(參考了美團的線程池文章)

ThreadPoolExecutor從繼承關系入手,整體采用分層設計:從頂層接口到抽象類,再到具體實現。以下按邏輯順序解析核心組件。

1. 頂層接口:Executor(任務提交與執行解耦)
  • 核心思想:將任務提交和任務執行分離,用戶無需關心線程創建或調度細節。
  • 工作方式:用戶提供Runnable對象(定義任務邏輯),Executor負責線程調配和任務執行。
  • 優勢:簡化并發編程,提升代碼可維護性。
2. 擴展接口:ExecutorService(增強任務管理和控制能力)
  • 功能擴展:在Executor基礎上,添加兩類關鍵能力:
    • 任務執行增強:支持異步任務處理,如生成Future對象(用于跟蹤一批任務結果)。
    • 線程池管控:提供停止線程池等方法(如shutdown()),實現更精細的資源控制。
3. 抽象類:AbstractExecutorService(串聯任務執行流程)
  • 承上啟下作用:作為ExecutorService的實現骨架,將任務執行流程標準化。
  • 設計目的:抽象通用邏輯(如任務提交、結果處理),確保子類僅需關注核心執行方法。
  • 簡化開發:降低底層實現復雜度,便于擴展新線程池類型。
4. 具體實現類:ThreadPoolExecutor(線程與任務協同管理)
  • 核心職責:作為最終實現,同時處理兩方面:
    • 生命周期維護:管理線程池狀態(如運行、關閉)。
    • 資源協調:高效調度線程與任務,實現并行執行(例如,通過工作隊列和線程復用機制)。
  • 核心參數說明(標紅部分是最核心的參數部分,也是需要關注配置的地方):
    • corePoolSize(核心線程數大小):不管它們創建以后是不是空閑的。線程池需要保持 corePoolSize 數量的線程,除非設置了 allowCoreThreadTimeOut。

    • maximumPoolSize(最大線程數):線程池中最多允許創建 maximumPoolSize 個線程。

    • keepAliveTime:(存活時間):如果經過 keepAliveTime 時間后,超過核心線程數的線程還沒有接受到新的任務,那就回收。

    • unit(keepAliveTime 的時間單位。)

    • workQueue(存放待執行任務的隊列):當提交的任務數超過核心線程數大小后,再提交的任務就存放在這里。它僅僅用來存放被 execute 方法提交的 Runnable 任務。

    • threadFactory(線程工程):用來創建線程工廠。比如這里面可以自定義線程名稱,看著名字就知道這個線程是哪里來的。

    • handler?(拒絕策略):當隊列里面放滿了任務、最大線程數的線程都在工作時,這時繼續提交的任務線程池就處理不了,應該執行怎么樣的拒絕策略。

2.2 線程池的執行流程

運行邏輯可分為兩個核心部分:

  1. 任務管理(生產者角色)
    當任務提交時,線程池根據當前狀態決定任務的流轉:

    • 如果線程可用,直接分配線程執行任務。
    • 如果線程繁忙,將任務緩沖到隊列中等待。
    • 如果系統過載,拒絕該任務。
  2. 線程管理(消費者角色)
    線程池維護一組線程,它們:

    • 主動獲取并執行任務。
    • 任務完成后,繼續從隊列中獲取新任務。
    • 當長時間無任務可獲取時,線程被回收以節省資源。

2.3 線程池中需要關注的幾個點

2.3.1 線程池狀態維護設計

線程池內部使用一個名為ctl的原子整數變量來高效維護運行狀態和線程數量,避免不一致性問題并提升性能。

1.?ctl變量的作用

private?final?AtomicInteger?ctl?=?new?AtomicInteger(ctlOf(RUNNING,?0));
  • ctl是一個整數變量(具體是AtomicInteger類型),它同時存儲兩個關鍵信息:
    • 運行狀態(runState):表示線程池的生命周期狀態(如運行中、關閉等),存儲在ctl的高3位。
    • 線程數量(workerCount):表示當前活躍線程的數量,存儲在ctl的低29位。
  • 用一個變量存儲兩個值,好處是:在決策時(如添加或移除線程),無需額外鎖來保證狀態和數量的一致性,提高了并發效率。
2.?位運算的原理
  • ctl的高3位和低29位互不干擾,通過位運算快速提取或組合值:
  • 這種設計基于二進制表示,例如:
    • 如果ctl的值是二進制xxx yyyyy...x代表高3位狀態,y代表低29位數量),則:
      • 提取狀態時,只保留高3位。
      • 提取數量時,只保留低29位。
3.?關鍵計算方法

線程池提供了三個方法來操作ctl

  • 獲取運行狀態runStateOf(c)?
    • 解釋:通過按位與操作,屏蔽掉低29位,只保留高3位的狀態值。
    • private?static?int?runStateOf(int?c){?return?c?&?~CAPACITY;?}?//計算當前運行狀態
  • 獲取線程數量workerCountOf(c)
    • 解釋:通過按位與操作,屏蔽掉高3位,只保留低29位的數量值。
    • private?static?int?workerCountOf(int?c){?return?c?&?CAPACITY;?}//計算當前線程數量

  • 組合狀態和數量ctlOf(rs, wc)
    • 解釋:通過按位或操作,將高3位的狀態和低29位的數量合并成一個新值。
    • private?static?int?ctlOf(int?rs,?int?wc)?{?return?rs?|?wc;?}?//通過狀態和線程數生成ctl

2.3.2 線程池中的參數可以動態修改嗎

當線程池在運行期調用?setCorePoolSize?方法設置新的?corePoolSize?值時,線程池會立即覆蓋原有的?corePoolSize?值。隨后,基于新值與原始值的比較結果,采取以下處理策略:

  • 如果新值小于當前工作線程數
    表明存在多余的 worker 線程。線程池會向當前空閑(idle)的 worker 線程發送中斷請求以啟動回收過程;多余的 worker 線程在下次空閑時也會被回收。

  • 如果新值大于原始值且任務隊列中有待執行任務
    線程池會創建新的 worker 線程,以執行隊列中的任務。

此設計確保了線程池資源能動態調整,以適應配置變化。

源碼中也寫了可以動態進行修改設置。

設置最大線程數量同時可以進行設置

2.3.3 核心線程數可以單獨進行設置嗎

此處需要注意的是最大線程數和核心線程數要一起進行設置。如果當前核心是3 最大線程是5,我們在單獨設置核心線程數為7,這個時候核心線程數會大于最大線程數。活躍線程數是不會變的,所以會出現設置出現問題,所以建議設置參數的時候一起進行設置

ava.util.concurrent.ThreadPoolExecutor#getTask

2.3.4? 隊列的數量怎么設置

隊列的 capacity 是被 final 修飾了,所以沒辦法進行設置,需要我們進行重寫一個類,把final去掉就可以設置線程池隊列的大小了。

2.3.4 線程池被創建后沒有任務過來,里面是不會有線程的,如何預熱。

2.3.4.1 全部啟動

2.3.4.2 只啟動一個

三、代碼實現

ok,下面進行代碼的展示,如何寫一個支持基于nacos動態刷新的分級線程池

3.1 監聽naocs的配置中心,如果有變化更新參數


/*** Nacos配置監聽,動態調整線程池參數*/
@RefreshScope
@Component
public class NacosThreadPoolConfig implements InitializingBean {private static final Logger logger = LoggerFactory.getLogger(DynamicStrategyTask.class);@Resourceprivate ThreadPoolManager threadPoolManager;@Autowiredprivate NacosConfigManager nacosConfigManager;@Autowiredprivate NacosConfigProperties nacosConfigProperties;/*** 監聽Nacos配置變化,動態調整線程池*/public void onConfigChange(String config) {try {// 解析為實體類ThreadPoolProperties TPconfig = YamlParser.parseToObject(config);// 處理高優先級線程池配置handleThreadPoolConfig(TPconfig, HIGH);// 處理中優先級線程池配置handleThreadPoolConfig(TPconfig, MEDIUM);// 處理低優先級線程池配置handleThreadPoolConfig(TPconfig, LOW);} catch (Exception e) {// 處理配置解析異常e.printStackTrace();}}private void handleThreadPoolConfig(ThreadPoolProperties configJson, PriorityEnum priority) {// 解析為Mapif(checkNotNull(configJson)){int core = configJson.getCore().getSize();int max = configJson.getMax().getSize();int queue = configJson.getQueue().getSize();switch (priority){case HIGH:core = core * 2;max  = max  * 2;break;case MEDIUM:queue = queue * 2;break;case LOW:core = core / 2;max = max / 2;queue = queue * 3;break;default:break;}threadPoolManager.adjustThreadPool(priority, core, max, queue);}}private boolean checkNotNull(ThreadPoolProperties configJson) {if (configJson == null || configJson.getCore()== null|| configJson.getMax() == null || configJson.getQueue() == null){return false;}return true;}@Overridepublic void afterPropertiesSet() throws Exception {//nacos配置變更監聽nacosConfigManager.getConfigService().addListener("thread-pool-config", nacosConfigProperties.getGroup(),new Listener() {@Overridepublic Executor getExecutor() {return null;}@Overridepublic void receiveConfigInfo(String configInfo) {//配置變更,修改線程池配置logger.info("線程池參數有變動請留意:【%s】",configInfo);onConfigChange(configInfo);}});}

3.2 構建優先級枚舉類及其注冊分級線程池

/*** 任務優先級枚舉*/
public enum PriorityEnum {HIGH(3),MEDIUM(2),LOW(1);private final int level;PriorityEnum(int level) {this.level = level;}public int getLevel() {return level;}public static PriorityEnum fromLevel(int level) {for (PriorityEnum priority : values()) {if (priority.level == level) {return priority;}}return MEDIUM;}
}

/*** 線程池配置類*/
@Configuration
@ConfigurationProperties(prefix = "threadpool")
public class ThreadPoolConfig {@Value("${threadpool.core-pool-size}")private Integer corePoolSize;@Value("${threadpool.maximum-pool-size}")private Integer maximumPoolSize;@Value("${threadpool.queue-capacity}")private Integer queueCapacity;/*** 高優先級線程池*/@Beanpublic DynamicThreadPool highPriorityThreadPool() {DynamicThreadPool threadPool = new DynamicThreadPool(PriorityEnum.HIGH);// 可以根據需要設置不同優先級線程池的默認參數threadPool.setCorePoolSize(corePoolSize * 2);threadPool.setMaxPoolSize(maximumPoolSize * 2);threadPool.setQueueCapacity(queueCapacity);threadPool.setThreadNamePrefix("High-Priority-Thread-");return threadPool;}/*** 中優先級線程池*/@Beanpublic DynamicThreadPool mediumPriorityThreadPool() {DynamicThreadPool threadPool = new DynamicThreadPool(PriorityEnum.MEDIUM);threadPool.setCorePoolSize(corePoolSize);threadPool.setMaxPoolSize(maximumPoolSize);threadPool.setQueueCapacity(queueCapacity * 2);threadPool.setThreadNamePrefix("Medium-Priority-Thread-");return threadPool;}/*** 低優先級線程池*/@Beanpublic DynamicThreadPool lowPriorityThreadPool() {DynamicThreadPool threadPool = new DynamicThreadPool(PriorityEnum.LOW);threadPool.setCorePoolSize(corePoolSize / 2);threadPool.setMaxPoolSize(maximumPoolSize / 2);threadPool.setQueueCapacity(queueCapacity * 3);threadPool.setThreadNamePrefix("Low-Priority-Thread-");return threadPool;}
}
/*** 動態線程池,支持動態調整參數*/
public class DynamicThreadPool extends ThreadPoolTaskExecutor {@Getterprivate final PriorityEnum priority;public DynamicThreadPool(PriorityEnum priority) {this.priority = priority;}/*** 動態調整線程池參數*/public void adjustParameters(int corePoolSize, int maximumPoolSize, int queueCapacity) {// 調整核心線程數setCorePoolSize(corePoolSize);// 調整最大線程數setMaxPoolSize(maximumPoolSize);setQueueCapacity(queueCapacity);}@Overrideprotected BlockingQueue<Runnable> createQueue(int queueCapacity) {if (queueCapacity > 0) {return new ResizeCapacityLinkedBlockingQueue<>(queueCapacity);}else {return new SynchronousQueue<>();}}
}

3.2 構建線程池管理類和可調整隊列

/*** 線程池管理器,管理不同優先級的線程池*/
@Component
public class ThreadPoolManager {// 用枚舉作為鍵存儲線程池private final Map<PriorityEnum, DynamicThreadPool> threadPools;// 自動注入所有DynamicThreadPool類型的Bean(key為Bean名稱,value為Bean實例)@Autowiredpublic ThreadPoolManager(List<DynamicThreadPool> dynamicThreadPools) {this.threadPools = new EnumMap<>(PriorityEnum.class);// 將Bean按名稱匹配到對應的枚舉for (DynamicThreadPool dtp : dynamicThreadPools) {try {// 假設Bean名稱與枚舉名一致(如"HIGH"對應PriorityEnum.HIGH)threadPools.put(dtp.getPriority(), dtp);} catch (IllegalArgumentException e) {// 處理不匹配的Bean名稱(可選:日志告警或忽略)System.out.println("未匹配到枚舉的線程池Bean:" + dtp.getPriority());}}}// 根據優先級獲取線程池public DynamicThreadPool getThreadPool(PriorityEnum priority) {return threadPools.get(priority);}/*** 提交任務到合適的線程池*/public <T> CompletableFuture<T> submit(PriorityTask<T> task) {PriorityEnum priority = task.getPriority();DynamicThreadPool threadPool = threadPools.get(priority);if (threadPool == null) {throw new IllegalArgumentException("No thread pool found for priority: " + priority);}// 可以根據任務預估時長做更精細的路由調整return CompletableFuture.supplyAsync(() -> {try {return task.call();} catch (Exception e) {throw new RuntimeException(e);}}, threadPool);}/*** 動態調整線程池參數*/public void adjustThreadPool(PriorityEnum priority, int corePoolSize, int maxPoolSize, int queueCapacity) {DynamicThreadPool threadPool = threadPools.get(priority);if (threadPool != null) {threadPool.adjustParameters(corePoolSize, maxPoolSize, queueCapacity);}}/*** 獲取線程池狀態信息*/public Map<String, Object> getThreadPoolStatus() {Map<String, Object> statusMap = new HashMap<>();threadPools.forEach((priority, pool) -> {Map<String, Object> poolStatus = new java.util.HashMap<>();poolStatus.put("corePoolSize", pool.getCorePoolSize());poolStatus.put("maxPoolSize", pool.getMaxPoolSize());poolStatus.put("queueCapacity", pool.getQueueCapacity());poolStatus.put("activeCount", pool.getActiveCount());poolStatus.put("queueSize", pool.getThreadPoolExecutor().getQueue().size());poolStatus.put("completedTaskCount", pool.getThreadPoolExecutor().getCompletedTaskCount());statusMap.put(priority.name(), poolStatus);});return statusMap;}
ublic class ResizeCapacityLinkedBlockingQueue<E> extends AbstractQueue<E>implements BlockingQueue<E>, java.io.Serializable {//其他省略private int capacity;
}

3.2 構建具體任務類 和 場景策略枚舉調用

public class DynamicStrategyTask implements PriorityTask<String> {private static final Logger logger = LoggerFactory.getLogger(DynamicStrategyTask.class);private final String taskName;private final PriorityEnum priority;private final EvenStrategyInterface strategy;private final BaseDomainEvent event;public DynamicStrategyTask(String taskName, PriorityEnum priority, EvenStrategyInterface strategy,BaseDomainEvent event) {this.taskName = taskName;this.priority = priority;this.strategy = strategy;this.event = event;}@Overridepublic PriorityEnum getPriority() {return priority;}@Overridepublic long estimateExecutionTime() {return 0;}@Overridepublic String call() throws Exception {// 模擬任務執行Date startTime = new Date();logger.info("任務【%s】開始執行,執行線程為【%s】,開始時間【%s】",taskName,Thread.currentThread().getName(), startTime);strategy.execute(event);Date endTime = new Date();long diff    = DateUtils.diff(endTime,startTime);logger.info("任務【%s】執行結束,執行線程為【%s】,結束時間【%s】,計時【%s】",taskName,Thread.currentThread().getName(), endTime,diff);return String.format("任務 [%s] 執行完成,優先級: %s,耗時: %dms",taskName, priority,diff);}
}
@Component
public class EvenStrategyContext {private static final Logger logger = LoggerFactory.getLogger(EvenStrategyContext.class);private EvenStrategyInterface strategy;@Autowiredprivate ThreadPoolManager threadPoolManager;public EvenStrategyContext getEvenStrategyContext(String cycleTypeCode) {if (EvenTypeEnum.getByDomainEvent(cycleTypeCode) == null || EvenTypeEnum.getByDomainEvent(cycleTypeCode).getEvenStrategyInterface() == null){this.strategy = null;}else{this.strategy = EvenTypeEnum.getByDomainEvent(cycleTypeCode).getEvenStrategyInterface();}return this;}public void execute(BaseDomainEvent event) {if (strategy == null){logger.info("沒有對應的監聽事件,以及對應的處理方法,請檢查傳入時間【%s】",event.getEventType());}else{threadPoolManager.submit(new DynamicStrategyTask(event.getEventType().getValue(), PriorityEnum.fromLevel(event.getEventType().getPriority()),strategy,event));}}
}

最后在說一下,關于線程池如何調整,美團給了一個公式,但是我目前還是根據經驗調整,監控動態線程池的執行情況適量進行調整,畢竟一般的公司服務器資源不是很充足,一個服務器可能部署很多的服務會占用線程資源,所以還得根據 實際情況,綜合進行考慮。

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

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

相關文章

Unity人形角色IK優化指南

目錄 Unity中人形角色的IKI 站立、奔跑IK 1. 接觸面法線 2. 調整質心位置 3. 保持原本朝向 攀爬IK 1. 四肢貼合 2. 保持身體與攀爬面的距離 3. 適應外拐角 瞄準IK 1. 頭部朝向 2. 手臂朝向 尾聲 本文將嘗試僅使用Untiy內置的Animator來解決常見的幾種運動所需的IK…

基于wireshark的USB 全速硬件抓包工具USB Sniffer Lite的使用

1、前言 隨著MCU的發展和需求的增多&#xff0c;USB已成為主流MCU的標配外設&#xff0c;但很多還是全速或低速IP&#xff0c;因此往往用不上高速抓包設備。 2、安裝wireshark和拷貝抓包插件 將抓包插件拷貝到wireshark的extcap目錄里&#xff0c;可參考基于wireshark的USB …

easyexcel模板導出Map數據時空值列被下一行列非空數據覆蓋

場景是&#xff1a;我用模板導出數據&#xff0c;sheet數據是一個List<String,Object>集合&#xff0c;然后發現第一行的第三列應該為空&#xff0c;但是不為空&#xff0c;填上了第二行的第三列數據&#xff1b;就像按列寫數據&#xff0c;碰到空值&#xff0c;下一行數…

并行Builder-輸出型流程編排的新思路

如果對于框架的介紹不感興趣的可以直接跳到Getting Started快速開始 在設計一款數據加載編排框架時&#xff0c;除了任何框架都必須具備的可靠性與穩定性之外&#xff0c;對于本次編排框架的設計&#xff0c;我們把核心目標放在高性能與易用性上。這不僅要求框架能夠快速、高效…

C#WPF實戰出真汁03--登錄界面設計

1、登錄界面設計要點簡潔直觀的布局 登錄界面應避免復雜元素&#xff0c;突出核心功能。通常包含用戶名/郵箱輸入框、密碼輸入框、登錄按鈕及可選功能&#xff08;如“記住我”“忘記密碼”&#xff09;。保持表單字段不超過5個&#xff0c;減少用戶認知負擔。清晰的視覺層次 通…

前端css學習筆記6:盒子模型

本文為個人學習總結&#xff0c;如有謬誤歡迎指正。前端知識眾多&#xff0c;后續將繼續記錄其他知識點&#xff01; 目錄 前言 一、組成 ?編輯content padding border margin margin塌陷 margin合并 使用場景 標題與段落間距 卡片列表布局 二、內容溢出—overflo…

以下是對智能電梯控制系統功能及系統云端平臺設計要點的詳細分析,結合用戶提供的梯控系統網絡架構設計和系統軟硬件組成,分點論述并補充關鍵要點:

智能電梯控制系統功能及系統云端平臺設計要點一、梯控系統網絡架構設計服務本地化&#xff1a;電梯門禁服務器本地化部署&#xff1a;核心服務器部署在項目本地&#xff0c;確保數據安全、運維及時性&#xff0c;減少網絡依賴。需支持本地獨立運行&#xff0c;避免云端故障影響…

全球電商業財一體化:讓出海品牌實現“看得見的增長“

內外貿并行的數字化挑戰在數字經濟浪潮下&#xff0c;中國品牌呈現"雙輪驅動"增長態勢&#xff1a;一邊深耕天貓、京東、抖音等國內主流平臺&#xff0c;一邊通過Amazon、Tiktok、eBay、Temu等渠道拓展全球市場。然而&#xff0c;多平臺、多幣種、多地區的復雜運營環…

Nacos-5--Nacos2.x版本的通信原理

Nacos 2.x引入了gRPC作為其主要的通信協議&#xff0c;取代1.x版本中的HTTP長輪詢和UDP通信方式&#xff0c;顯著提升了性能、實時性和穩定性。gRPC是一個高性能、開源的遠程過程調用&#xff08;RPC&#xff09;框架&#xff0c;它基于HTTP/2標準設計&#xff0c;并使用Protoc…

如何以開發者的身份開發出比python更好的應用軟件?

作為一名擁有多年軟件架構經驗的開發者,我見證了Python從實驗室腳本語言成長為數字時代基礎設施的完整歷程。2008年我參與歐洲核子研究中心的粒子數據分析系統時,Python還是輔助工具,而今天它已成為驅動LIGO引力波探測的核心引擎——這種躍遷絕非偶然。 一、Python的巔峰應…

zynq代辦事項

測試verilog按鍵 1.0 按鍵->隊列->串口 1.1 按鍵模塊ming_key包括 按下,松開,單擊,雙擊,長按,事件 1.2 隊列模塊ming_fifo存儲按鍵發出的[事件和事件戳] 1.3 頂層模塊TOP 輪詢 ming_fifo,將讀到的事件用串口封裝成數據包發給串口助手 測試zynq的M_AXI_GP0 1.0 用axi_li…

【Redis】Redis典型應用——緩存

目錄 一.什么是緩存 二.使用Redis作為緩存 2.1.關系型數據庫的缺點 2.2.使用Redis作為MySQL的緩存 三. 緩存更新策略:識別熱點數據 3.1.定期更新 3.2.實時生成 四.緩存的使用注意事項 4.1.緩存預熱(Cache preheating) 4.2.關于緩存穿透 (Cache penetration) 4.3..關…

C#控制臺項目,鼠標點擊后線程會暫停

C#控制臺應用程序&#xff0c;點擊后就會暫停運行&#xff0c;但是我想讓它運行不受鼠標點擊的影響。 下面是程序演示&#xff1a;class Program{static void Main(string[] args){Console.WriteLine("Hello");int index 0;while(true){Console.WriteLine($"in…

云計算-實戰 OpenStack 私有云運維:服務部署、安全加固、性能優化、從服務部署到性能調優(含數據庫、內核、組件優化)全流程

簡介 此次圍繞OpenStack 私有云平臺的運維與開發展開,涵蓋了從核心服務安裝到深度優化的全流程實戰內容。文中詳細介紹了 OpenStack 各關鍵組件(如 Keystone、Glance、Nova、Neutron、Cinder 等)的安裝部署方法,包括使用腳本快速搭建服務、創建用戶、上傳鏡像、配置網絡等…

流水的 AI,鐵打的騰訊

騰訊 昨天騰訊公布了 2025 年第二季度的業績報告。 就還是那只鵝&#xff0c;就還是那個超預期。 總營收 1845 億&#xff0c;同比增長 15%&#xff1b;凈利潤 556.3 億&#xff0c;同比增長 17%&#xff1b;經營利潤 692.5 億&#xff0c;同比增長 18%。 這里面最炸裂的&#…

再回C的進制轉換--負數

概念 負數在計算機中以補碼的形式保存&#xff0c;以int類型的-15為例&#xff0c;求補碼先對-15取絕對值&#xff0c;然后對其按位取反(得到反碼)&#xff0c;然后加1&#xff0c;就可以得到其的補碼。 二進制的補碼 -15 (取絕對值)–> 15 --> (十六進制表示)0x000f (按…

項目績效域-筆記

一、項目管理績效域 1. 價值驅動的項目管理知識體系 1&#xff09;體系構成要素 核心轉變&#xff1a;從預測型生命周期&#xff08;計劃驅動&#xff09;轉向價值驅動體系&#xff0c;融合預測型和敏捷方法組成要素&#xff1a; 12個項目管理原則&#xff08;基礎&#xff09;…

怎么判斷晶振的好壞,有什么簡單的辦法

今天來聊聊晶振的好壞判斷方法&#xff0c;3個步驟輕松搞定。外觀檢查&#xff1a;先看臉&#xff0c;再看腳晶振體積雖小&#xff0c;但問題往往寫在“臉上”。第一步&#xff0c;用肉眼觀察&#xff1a;裂痕與破損&#xff1a;晶振表面如果有明顯裂紋或缺口&#xff0c;大概率…

mac下載maven并配置,以及idea配置

文章目錄下載配置settingsidea配置下載 https://maven.apache.org/download.cgi 我下的3.6.3 https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/ 配置 open ~/.zprofile添加&#xff0c;根據自己安裝路徑修改 export MAVEN_HOME/Users/xxx/tools/apache-mave…

基于機器視覺的車道線檢測與跟蹤關鍵技術研究

摘 要 隨著自動駕駛技術的迅速發展&#xff0c;車道線檢測與跟蹤技術在提高道路安全性和駕駛自動化水平方面發揮著至關重要的作用。本文針對基于機器視覺的車道線檢測與跟蹤關鍵技術進行了深入研究&#xff0c;旨在提升車道線檢測的準確性與系統的實時響應能力。通過采用先進的…