多線程向設備發送數據

需求:做一個部門授權,可以把所選擇部門下面的所有人的人臉信息傳到設備組里(多個設備),問題在于圖片是通過Base64處理之后的,會導致文件名非常長,如果一次性傳很多數據就會超過設備的最長請求長度,如果不用Base64處理的話讓設備自己去minio下載就會導致特別慢,設備容易掉線,所以就用多線程發送。先看一下全部的代碼,再看一下多線程的方法。

全部代碼:

@Overridepublic List<Long> createDeptAuthorize(DeptAuthorizeSaveReqVO createReqVO) {List<Long> ids = new ArrayList<>();List<Long> userIds = new ArrayList<>();//遍歷部門表,查看該部門是否已有授權List<Long> deptAuthorizeExits = new ArrayList<>();List<Long> deptAuthorizeNotExits = new ArrayList<>();//設備數組List<BaseDeviceDo> baseDeviceDos = new ArrayList<>();//把待更新授權的人員id存在這個數組里List<Long> userUpdateIds = new ArrayList<>();//把待更新授權的人員存在這個數組里List<AdminUserRespDTO> userUpdateList = new ArrayList<>();// 設置用戶信息List<User> userList = new ArrayList<>();for (Long l : createReqVO.getDeptId()) {QueryWrapper<DeptAuthorizeDO> queryWrapperDept = new QueryWrapper<>();queryWrapperDept.eq("dept_id", l);queryWrapperDept.eq("deleted", 0);DeptAuthorizeDO deptAuthorizeDO1 = deptAuthorizeMapper.selectOne(queryWrapperDept);if (deptAuthorizeDO1 != null) {//表里存在這條數據就代表已有部門授權,所以要修改部門授權deptAuthorizeExits.add(deptAuthorizeDO1.getDeptId());}else{deptAuthorizeNotExits.add(l);}}//先遍歷不存在的部門授權,即新增授權并發到設備上for (Long l : deptAuthorizeNotExits) {// 插入DeptAuthorizeDO deptAuthorize = new DeptAuthorizeDO();deptAuthorize.setDeptId(l);deptAuthorize.setAuthorizeWay(createReqVO.getAuthorizeWay());deptAuthorize.setDoorId(createReqVO.getDoorId());deptAuthorize.setDoorGroupId(createReqVO.getDoorGroupId());deptAuthorize.setEffectMethod(createReqVO.getEffectMethod());deptAuthorize.setInPeriodId(createReqVO.getInPeriodId());deptAuthorize.setOutPeriodId(createReqVO.getOutPeriodId());deptAuthorizeMapper.insert(deptAuthorize);// 假設deptAuthorizeMapper.insert()返回插入記錄的IDids.add(deptAuthorize.getId());//查找這個部門下面有多少人List<AdminUserRespDTO> adminUserDOList = adminUserApi.getUserListByDeptId(l);for (AdminUserRespDTO adminUserDO : adminUserDOList) {//遍歷人員數組看看是否在授權生效表里QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("user_id", adminUserDO.getId());queryWrapper.eq("deleted", 0);AuthorizeEffectDO authorizeEffectDO = authorizeEffectMapper.selectOne(queryWrapper);if (authorizeEffectDO == null) {//如果不存在就插入這條數據AuthorizeEffectDO authorizeEffectDO1 = new AuthorizeEffectDO();authorizeEffectDO1.setUserId(adminUserDO.getId());//0代表部門授權authorizeEffectDO1.setAuthorizeEffectType(0);//0代表非臨時授權authorizeEffectDO1.setIsTemporary(0);authorizeEffectMapper.insert(authorizeEffectDO1);userIds.add(adminUserDO.getId());//插入授權日志(生效表里沒有這條數據則代表這人沒有授權所以肯定會授權成功)AuthorizeLogDO authorizeLogDO = new AuthorizeLogDO();//授權idauthorizeLogDO.setAuthorizeId(deptAuthorize.getId());//授權類型(0:部門 1:特殊 2:個人 3:臨時)authorizeLogDO.setAuthorizeType(0);//用戶idauthorizeLogDO.setUserId(adminUserDO.getId());//備注authorizeLogDO.setRemark("創建部門授權成功");//是否成功(0:成功 1:失敗)authorizeLogDO.setIsSuccess(0);//插入authorizeLogMapper.insert(authorizeLogDO);} else {//如果不存在這條數據則把生效設置為1//臨時>人>特殊>部門if (authorizeEffectDO.getAuthorizeEffectType() != 1 && authorizeEffectDO.getAuthorizeEffectType() != 2) {//0代表部門授權authorizeEffectDO.setAuthorizeEffectType(0);authorizeEffectMapper.updateById(authorizeEffectDO);userIds.add(adminUserDO.getId());//插入授權日志(生效表里沒有這條數據則代表這人沒有授權所以肯定會授權成功)AuthorizeLogDO authorizeLogDO = new AuthorizeLogDO();//授權idauthorizeLogDO.setAuthorizeId(deptAuthorize.getId());//授權類型(0:部門 1:特殊 2:個人 3:臨時)authorizeLogDO.setAuthorizeType(0);//用戶idauthorizeLogDO.setUserId(adminUserDO.getId());//備注authorizeLogDO.setRemark("創建部門授權成功");//是否成功(0:成功 1:失敗)authorizeLogDO.setIsSuccess(0);//插入authorizeLogMapper.insert(authorizeLogDO);} else {//記錄在授權日志里//插入授權日志(失敗)AuthorizeLogDO authorizeLogDO = new AuthorizeLogDO();//授權idauthorizeLogDO.setAuthorizeId(deptAuthorize.getId());//授權類型(0:部門 1:特殊 2:個人 3:臨時)authorizeLogDO.setAuthorizeType(0);//用戶idauthorizeLogDO.setUserId(adminUserDO.getId());//備注authorizeLogDO.setRemark("創建部門授權失敗,已有更高授權");//是否成功(0:成功 1:失敗)authorizeLogDO.setIsSuccess(1);//插入authorizeLogMapper.insert(authorizeLogDO);}}}List<AdminUserRespDTO> adminUserDOS =adminUserApi.getUserListByDeptId(l);for (AdminUserRespDTO adminUserDO : adminUserDOS) {//更新這個部門下面人的權限//用戶列表User user = new User();AdminUserRespDTO user1 = adminUserApi.getUser(adminUserDO.getId());user.setI(user1.getUserSn());user.setN(user1.getNickname());user.setU(user1.getUserSn());user.setC("");user.setB("");user.setW(user1.getPassword());user.setD(user1.getDeptName());//出門規則if (createReqVO.getAuthorizeWay()==0) {//門授權,判斷這個門下的設備是進門還是出門List<DoorDeviceRelateRespDTO> doorDeviceRelateList = doorDeviceRelateApi.getDoorDeviceRelateList(createReqVO.getDoorId());for (DoorDeviceRelateRespDTO doorDeviceRelateRespDTO : doorDeviceRelateList) {if (doorDeviceRelateRespDTO != null && doorDeviceRelateRespDTO.getInOutDirection() == 0){//存在并且為進門(0進門 1出門)
//                                Long inPeriodId = accessPeriodMapper.selectById(createReqVO.getInPeriodId()).getParentRuleId();user.setM(createReqVO.getInPeriodId().toString());}else if (doorDeviceRelateRespDTO != null && doorDeviceRelateRespDTO.getInOutDirection() == 1){//存在并且為出門(0進門 1出門)
//                                AccessPeriodDO accessPeriodDO = accessPeriodMapper.selectById(createReqVO.getOutPeriodId());
////                                Long outPeriodId = accessPeriodMapper.selectById(createReqVO.getOutPeriodId()).getParentRuleId();user.setM(createReqVO.getOutPeriodId().toString());}}}else if (createReqVO.getAuthorizeWay() == 1){//獲取這個門組下面的門QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("group_id",createReqVO.getDoorGroupId());queryWrapper.eq("deleted",0);List<GroupDoorRelateDO> doorRelateDOS = doorRelateMapper.selectList(queryWrapper);for (GroupDoorRelateDO doorRelateDO : doorRelateDOS) {List<DoorDeviceRelateRespDTO> doorDeviceRelateList = doorDeviceRelateApi.getDoorDeviceRelateList(doorRelateDO.getDoorId());for (DoorDeviceRelateRespDTO doorDeviceRelateRespDTO : doorDeviceRelateList) {if (doorDeviceRelateRespDTO != null && doorDeviceRelateRespDTO.getInOutDirection() == 0){//存在并且為進門(0進門 1出門)user.setM(createReqVO.getOutPeriodId().toString());}else if (doorDeviceRelateRespDTO != null && doorDeviceRelateRespDTO.getInOutDirection() == 1){//存在并且為出門(0進門 1出門)user.setM(createReqVO.getOutPeriodId().toString());}}}}//照片FaceImageRespDTO faceImageDO = faceImageApi.getFaceImage(user1.getId());if (faceImageDO != null) {if (faceImageDO.getImage() != null && !faceImageDO.getImage().isEmpty()) {// minio路徑轉換為文件路徑String objectName = faceImageDO.getImage().split("/")[faceImageDO.getImage().split("/").length - 1];// 從 MinIO 下載文件并轉換為字節數組byte[] fileBytes = minioToBase64.downloadFileFromMinio(objectName);// 轉換為 Base64 字符串String base6String4 = minioToBase64.convertToBase64(fileBytes);user.setF(base6String4);}}//放到user列表里傳給設備userList.add(user);}}//遍歷已有部門授權列表,即修改現有的部門授權for (Long deptAuthorizeExit : deptAuthorizeExits) {QueryWrapper queryWrapperDeptAuthorize = new QueryWrapper();queryWrapperDeptAuthorize.eq("dept_id",deptAuthorizeExit);queryWrapperDeptAuthorize.eq("deleted",0);//修改部門授權DeptAuthorizeDO deptAuthorizeDO = deptAuthorizeMapper.selectOne(queryWrapperDeptAuthorize);//更新部門授權列表的基礎性徐deptAuthorizeDO.setAuthorizeWay(createReqVO.getAuthorizeWay());deptAuthorizeDO.setDoorId(createReqVO.getDoorId());deptAuthorizeDO.setDoorGroupId(createReqVO.getDoorGroupId());deptAuthorizeDO.setEffectMethod(createReqVO.getEffectMethod());deptAuthorizeDO.setInPeriodId(createReqVO.getInPeriodId());deptAuthorizeDO.setOutPeriodId(createReqVO.getOutPeriodId());deptAuthorizeDO.setUpdateTime(LocalDateTime.now());deptAuthorizeMapper.updateById(deptAuthorizeDO);//查找這個部門下面有多少人List<AdminUserRespDTO> adminUserDOList = adminUserApi.getUserListByDeptId(deptAuthorizeExit);for (AdminUserRespDTO adminUserDO : adminUserDOList) {//遍歷人員數組看看是否在授權生效表里有高于部門授權的授權,如果有則不授權QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("user_id", adminUserDO.getId());//目前生效類型為部門授權queryWrapper.eq("authorize_effect_type",0);queryWrapper.eq("deleted",0);AuthorizeEffectDO authorizeEffectDO = authorizeEffectMapper.selectOne(queryWrapper);if (authorizeEffectDO != null) {//把符合規定的人插入到待更新的userId數組中userUpdateIds.add(authorizeEffectDO.getUserId());userUpdateList.add(adminUserApi.getUser(authorizeEffectDO.getUserId()));}}for (AdminUserRespDTO adminUserRespDTO : userUpdateList) {//更新這個部門下面人的權限//用戶列表User user = new User();AdminUserRespDTO user1 = adminUserApi.getUser(adminUserRespDTO.getId());user.setI(user1.getUserSn());user.setN(user1.getNickname());user.setU(user1.getUserSn());user.setC("");user.setB("");user.setW(user1.getPassword());user.setD(user1.getDeptName());//出門規則if (createReqVO.getAuthorizeWay()==0) {//門授權,判斷這個門下的設備是進門還是出門List<DoorDeviceRelateRespDTO> doorDeviceRelateList = doorDeviceRelateApi.getDoorDeviceRelateList(createReqVO.getDoorId());for (DoorDeviceRelateRespDTO doorDeviceRelateRespDTO : doorDeviceRelateList) {if (doorDeviceRelateRespDTO != null && doorDeviceRelateRespDTO.getInOutDirection() == 0){//存在并且為進門(0進門 1出門)
//                                Long inPeriodId = accessPeriodMapper.selectById(createReqVO.getInPeriodId()).getParentRuleId();user.setM(createReqVO.getInPeriodId().toString());}else if (doorDeviceRelateRespDTO != null && doorDeviceRelateRespDTO.getInOutDirection() == 1){//存在并且為出門(0進門 1出門)
//                                AccessPeriodDO accessPeriodDO = accessPeriodMapper.selectById(createReqVO.getOutPeriodId());
////                                Long outPeriodId = accessPeriodMapper.selectById(createReqVO.getOutPeriodId()).getParentRuleId();user.setM(createReqVO.getOutPeriodId().toString());}}}else if (createReqVO.getAuthorizeWay() == 1){//獲取這個門組下面的門QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("group_id",createReqVO.getDoorGroupId());queryWrapper.eq("deleted",0);List<GroupDoorRelateDO> doorRelateDOS = doorRelateMapper.selectList(queryWrapper);for (GroupDoorRelateDO doorRelateDO : doorRelateDOS) {List<DoorDeviceRelateRespDTO> doorDeviceRelateList = doorDeviceRelateApi.getDoorDeviceRelateList(doorRelateDO.getDoorId());for (DoorDeviceRelateRespDTO doorDeviceRelateRespDTO : doorDeviceRelateList) {if (doorDeviceRelateRespDTO != null && doorDeviceRelateRespDTO.getInOutDirection() == 0){//存在并且為進門(0進門 1出門)user.setM(createReqVO.getOutPeriodId().toString());}else if (doorDeviceRelateRespDTO != null && doorDeviceRelateRespDTO.getInOutDirection() == 1){//存在并且為出門(0進門 1出門)user.setM(createReqVO.getOutPeriodId().toString());}}}}//照片FaceImageRespDTO faceImageDO = faceImageApi.getFaceImage(user1.getId());if (faceImageDO != null) {if (faceImageDO.getImage() != null && !faceImageDO.getImage().isEmpty()) {// minio路徑轉換為文件路徑String objectName = faceImageDO.getImage().split("/")[faceImageDO.getImage().split("/").length - 1];// 從 MinIO 下載文件并轉換為字節數組byte[] fileBytes = minioToBase64.downloadFileFromMinio(objectName);// 轉換為 Base64 字符串String base6String4 = minioToBase64.convertToBase64(fileBytes);user.setF(base6String4);}}//放到user列表里傳給設備userList.add(user);}}//判斷相關聯的門找到要傳輸的設備if (createReqVO.getAuthorizeWay() == 0){//門授權//獲得這個門下面的所有設備List<DoorDeviceRelateRespDTO> doorDeviceRelateList = doorDeviceRelateApi.getDoorDeviceRelateList(createReqVO.getDoorId());for (DoorDeviceRelateRespDTO doorDeviceRelateRespDTO : doorDeviceRelateList) {OnsiteEquipDO onsiteEquipDO = onsiteEquipMapper.selectById(doorDeviceRelateRespDTO.getDeviceId());//插入設備列表BaseDeviceDo baseDeviceDo = new BaseDeviceDo();baseDeviceDo.setDeviceType(onsiteEquipDO.getDeviceModel());baseDeviceDo.setIpAddr(onsiteEquipDO.getDeviceIp());baseDeviceDo.setPassword(onsiteEquipDO.getDevicePassword());baseDeviceDos.add(baseDeviceDo);}}else if (createReqVO.getAuthorizeWay() == 1){//門組授權//獲得門組下的所有設備List<OnsiteEquipDO> onsiteEquipDOS = groupDoorRelateService.listByAccessGroupTableId(createReqVO.getDoorGroupId());onsiteEquipDOS.stream().forEach(onsiteEquipDO -> {BaseDeviceDo baseDeviceDo = new BaseDeviceDo();baseDeviceDo.setDeviceType(onsiteEquipDO.getDeviceModel());baseDeviceDo.setIpAddr(onsiteEquipDO.getDeviceIp());baseDeviceDo.setPassword(onsiteEquipDO.getDevicePassword());baseDeviceDos.add(baseDeviceDo);});}// 創建線程池ExecutorService executorService = Executors.newFixedThreadPool(3);// 分批處理用戶列表int batchSize = 5;int totalTasks = (userList.size() + batchSize - 1) / batchSize;for (int i = 0; i < totalTasks; i++) {int start = i * batchSize;int end = Math.min(start + batchSize, userList.size());List<User> usersBatch = userList.subList(start, end);executorService.submit(() -> {control.setDeviceUser(baseDeviceDos, usersBatch);});}// 關閉線程池executorService.shutdown();try {// 等待所有任務完成executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);} catch (InterruptedException e) {e.printStackTrace();}return ids;}

多線程方法:

// 創建線程池ExecutorService executorService = Executors.newFixedThreadPool(3);// 分批處理用戶列表int batchSize = 5;int totalTasks = (userList.size() + batchSize - 1) / batchSize;for (int i = 0; i < totalTasks; i++) {int start = i * batchSize;int end = Math.min(start + batchSize, userList.size());List<User> usersBatch = userList.subList(start, end);executorService.submit(() -> {control.setDeviceUser(baseDeviceDos, usersBatch);});}// 關閉線程池executorService.shutdown();try {// 等待所有任務完成executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);} catch (InterruptedException e) {e.printStackTrace();}

1. 創建線程池

ExecutorService executorService = Executors.newFixedThreadPool(3);

  • 使用 Executors.newFixedThreadPool(3) 創建了一個固定大小為 3 的線程池。

  • 線程池的作用是管理線程的生命周期,避免頻繁創建和銷毀線程帶來的性能開銷。

  • 在這個線程池中,最多可以同時運行 3 個線程。

每次運行三個線程可以解決掉請求頭過長的問題。

2. 計算分批處理的批次數量

int batchSize = 5;
int totalTasks = (userList.size() + batchSize - 1) / batchSize;

  • batchSize 定義了每一批次處理的用戶數量,這里設置為 5。

  • totalTasks 計算總共需要處理的批次數量。通過公式 (userList.size() + batchSize - 1) / batchSize,確保即使用戶數量不能被 batchSize 整除,也能正確計算出需要的批次數量。

3. 分批處理用戶列表

for (int i = 0; i < totalTasks; i++) {
int start = i * batchSize;
int end = Math.min(start + batchSize, userList.size());
List<User> usersBatch = userList.subList(start, end);
executorService.submit(() -> {
control.setDeviceUser(baseDeviceDos, usersBatch);
});
}

  • 循環邏輯

    • 外層循環 for (int i = 0; i < totalTasks; i++) 遍歷所有批次。

  • 計算每一批次的范圍

    • int start = i * batchSize; 計算當前批次的起始索引。

    • int end = Math.min(start + batchSize, userList.size()); 計算當前批次的結束索引,確保不會超出 userList 的范圍。

  • 提取當前批次的用戶子列表

    • List<User> usersBatch = userList.subList(start, end); 使用 subList 方法從 userList 中提取當前批次的用戶子列表。

  • 提交任務到線程池

    • executorService.submit(() -> { control.setDeviceUser(baseDeviceDos, usersBatch); }); 將任務提交到線程池中執行。

    • 每個任務調用 control.setDeviceUser(baseDeviceDos, usersBatch) 方法,處理當前批次的用戶。

4. 關閉線程池并等待所有任務完成

executorService.shutdown();
try {
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}

  • 關閉線程池

    • executorService.shutdown(); 調用 shutdown() 方法,表示不再接受新的任務,但會等待已經提交的任務完成。

  • 等待所有任務完成

    • executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 調用 awaitTermination 方法,等待線程池中的所有任務完成。

    • 這里使用 Long.MAX_VALUETimeUnit.NANOSECONDS,表示等待時間非常長,幾乎等同于無限等待。

  • 異常處理

    • 如果線程被中斷,會拋出 InterruptedException,捕獲并打印堆棧信息。

這樣就可以實現多線程向設備發送數據了。

另:附上設備發送數據的方法,也是多線程,可以參考。

/*** 設置設備用戶(正式員工、常駐)*/public List<ReturnMessage> setDeviceUser(List<BaseDeviceDo> baseDeviceDos, List<User> list) {List<ReturnMessage> failureMessages = new ArrayList<>();ExecutorService executor = Executors.newFixedThreadPool(baseDeviceDos.size());List<Runnable> tasks = new ArrayList<>();for (BaseDeviceDo baseDeviceDo : baseDeviceDos) {tasks.add(() -> {ReturnMessage returnMessage = null;try {switch (baseDeviceDo.getDeviceType()) {case M7:returnMessage = m7Control.setDeviceUser(baseDeviceDo, list);}if (returnMessage != null && !returnMessage.getCode().equals("0")) {failureMessages.add(returnMessage);}} catch (Exception e) {e.printStackTrace();// 將異常信息封裝到 ReturnMessage 中,或者創建一個新的 ReturnMessage 來表示失敗returnMessage.setCode("50100");returnMessage.setMsg("處理設備類型 " + baseDeviceDo.getDeviceType() + "設備IP為:" + baseDeviceDo.getIpAddr() + " 時發生異常: " + e.getMessage());failureMessages.add(returnMessage);}});}tasks.forEach(executor::submit);executor.shutdown();while (!executor.isTerminated()) {// 等待所有線程完成}return failureMessages;}

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

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

相關文章

Buck的Loadline和DVS區別和聯系

Buck 電路設計中&#xff0c;有兩個概念&#xff0c;一個是Load-Line&#xff0c;一個是DVS&#xff0c;它們的含義是什么呢。 Load-Line&#xff08;也稱為有源電壓定位&#xff0c;AVP&#xff09;是通過調整BUCK電路的輸出電壓&#xff0c;使其根據負載電流動態變化的技術。…

MySQL會話連接數消耗內存分析

關于連接數消耗內存情況 FROM DEEPSEEK 在 MySQL 中&#xff0c;每個單獨的空閑連接所消耗的內存量取決于多個因素&#xff0c;包括連接的線程棧大小&#xff08;由 thread_stack 參數設置&#xff09;和其他每個連接的緩沖區。根據測試結果來看&#xff0c;對于空閑連接的內…

Objective-C實現調節筆記本屏幕亮度(附完整源碼)

Objective-C實現調節筆記本屏幕亮度 在macOS上,您可以使用Objective-C來調節筆記本的屏幕亮度。以下是一個簡單的示例,演示如何使用CoreGraphics框架來實現這一功能。請確保您的Xcode項目中包含CoreGraphics框架。 完整源碼示例 #import <Cocoa/Cocoa.h> #import <…

三十一、【Linux網站服務器】搭建httpd服務器演示個人主頁、用戶認證、https加密網站配置

httpd服務器功能演示一、安裝 HTTPD 服務二、配置個人用戶主頁1. 啟用個人空間功能2. 創建測試用戶及網站目錄3. 配置 SELinux 權限三、配置用戶認證1. 創建密碼文件2. 配置目錄認證3. 重啟服務生效四、配置 SSL 加密網站1. 生成自簽名證書2. 配置 SSL 虛擬主機3. 重啟服務驗證…

把Java程序部署到本地Docker

一&#xff1a;clean && install程序install之后會在target中生成jar包 二&#xff1a;準備三個文件&#xff08;1&#xff09;其中Dockerfile主要起到配置作用&#xff1a;# 基礎鏡像 FROM openjdk:17-jdk-slim # 作者 MAINTAINER "" # 配置 ENV PAR…

Java學習-------外觀模式

在軟件開發中&#xff0c;隨著系統的不斷迭代&#xff0c;模塊會越來越多&#xff0c;模塊之間的依賴關系也會變得錯綜復雜。這不僅會增加開發難度&#xff0c;還會讓系統的維護和擴展變得棘手。而外觀模式就像一位 “前臺接待員”&#xff0c;為復雜的系統提供一個簡潔統一的接…

Go語言-->變量

Go語言–>變量 在 Go 語言中&#xff0c;定義變量有幾種常見的方式。下面是一些常見的語法和用法&#xff1a; 1. 使用 var 關鍵字定義變量 最常見的方式是使用 var 關鍵字&#xff0c;后面跟上變量名和類型。你也可以為變量賦初值。 基本格式&#xff1a; var variableName…

分布式鏈路追蹤的實現原理

分布式鏈路追蹤系統的實現涉及多個核心技術環節&#xff0c;下面我將從數據采集、上下文傳播、存儲分析等維度深入解析其工作原理。 一、核心架構組件 1. 系統組成模塊 #mermaid-svg-pDlZY54w2Z0Bp1H1 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-si…

Python爬蟲實戰:研究micawber庫相關技術構建網頁采集系統

1. 引言 1.1 研究背景與意義 在當今信息爆炸的時代,互聯網上的數據量呈現出爆炸式增長。如何從海量的網頁數據中提取有價值的信息,成為了一個重要的研究課題。網絡爬蟲作為一種自動獲取網頁內容的技術,為解決這一問題提供了有效的手段。通過網絡爬蟲,可以快速、高效地采集…

前端框架Vue3(三)——路由和pinia

路由的理解 路由就是一組key-value的對應關系&#xff0c;多個路由&#xff0c;需要經過路由器的管理。 路由-基本切換效果 導航區、展示區請來路由器制定路由的具體規則&#xff08;什么路徑&#xff0c;對應著什么組件&#xff09;形成一個一個的路由 【兩個注意點】 路由組件…

【go】實現BMI計算小程序與GUI/WEB端實現

好的&#xff0c;下面是用 Go 語言實現的一個簡單的 BMI&#xff08;Body Mass Index&#xff0c;身體質量指數&#xff09;計算器&#xff0c;包含中文注釋與完整代碼&#xff0c;可以直接運行。 一、BMI 計算公式 BMI體重&#xff08;kg&#xff09;身高2&#xff08;m2&…

Windows系統優化命令-記錄

閑著無聊&#xff0c;近來電腦有些卡頓&#xff0c;記錄一下相關命令。最好的命令還是格式化╮(╯▽╰)╭ 1. 磁盤清理相關命令 cleanmgr - 磁盤清理工具 cleanmgr啟動磁盤清理工具&#xff0c;可清理臨時文件、回收站等內容 diskpart - 磁盤分區工具 diskpart用于磁盤管理&…

BFCP協議學習

BFCP是為了SIP呼叫中實現presentation的二進制協議。開源庫libbfcp 如何協商角色 SIP 消息的SDP中有BFCP 的部分&#xff0c;其中s-only 代表要當服務器角色&#xff0c;c-only 代表要當client角色。confid, userid 都是需要在后續消息中對齊的。 通過port信息可以為后續bfcp…

常用設計模式系列(十七)—命令模式

常用設計模式系列&#xff08;十七&#xff09;—命令模式 第一節、前言 各位老鐵好&#xff01; 今天我來跟大家分享對象行為型模式第二章節——《命令模式》&#xff0c;“命令”一詞&#xff0c;通俗易懂&#xff0c;我們在生活中經常會發出各種各樣的命令&#xff0c;就像你…

【AI繪畫】Stable Diffusion 全面指南:安裝、版本對比、功能解析與高級應用

引言&#xff1a;Stable Diffusion 概述 在人工智能圖像生成領域&#xff0c;商業工具如Midjourney憑借其集成化服務與高質量輸出占據市場&#xff0c;而Stable Diffusion&#xff08;簡稱SD&#xff09;則以開源特性構建了差異化優勢。與商業工具依賴云端資源、受限于訂閱費用…

kafka使用kraft

window 使用kafka-storage生成生成一個uuid .\kafka-storage.bat random-uuid格式化存儲 在這里插入代碼片.\kafka-storage.bat format -t 對應的uuid D:\configure\fisher\kafka\config\kraft\server.properties 啟動命令 .\kafka-server-start.bat D:\configure\fisher\kafka…

HCIA-Datacom認證筆記:IP路由基礎——核心概念與路由分類

網絡技術學習中&#xff0c;IP路由是繞不開的核心知識點&#xff0c;對于備考HCIA-Datacom認證的朋友來說&#xff0c;掌握路由基礎能為后續學習打下良好基礎。今天帶朋友們梳理一下IP路由的核心概念、路由表結構及路由分類一、路由核心概念什么是路由&#xff1f; 簡單來說&am…

FFmpeg 安裝與使用

文章目錄1. 環境部署&#xff08;Windows&#xff09;1.1. 安裝包下載1.2. 配置環境變量1.3. 驗證安裝2. FFmpeg 基礎使用教程2.1. 常用命令格式2.2. 基礎功能示例2.2.1. 視頻轉碼&#xff08;MP4 → MKV&#xff09;2.2.2. 調整分辨率&#xff08;1080p → 480p&#xff09;2.…

Python 數據分析(四):Pandas 進階

目錄 1. 概述2. 缺失項3. 分組聚合4. 數據合并5. 數據可視化 5.1 折線圖5.2 條形圖5.3 直方圖5.4 散點圖5.5 餅圖 1. 概述 我們在上一篇文章初識 Pandas中已經對 Pandas 作了一些基本介紹&#xff0c;本文我們進一步來學習 Pandas 的一些使用。 2. 缺失項 在現實中我們獲…

結構化文本文檔的內容抽取與版本重構策略

結構化文本文檔的內容抽取與版本重構策略 摘要 本文深入探討了結構化文本文檔處理領域中的兩大核心技術——內容抽取與版本重構。文章首先分析了結構化文檔的特點及其在現代信息管理中的重要性&#xff0c;隨后系統性地介紹了文檔內容抽取的技術路線與方法論&#xff0c;包括…