基于WebSockets和OpenCV的安卓眼鏡視頻流GPU硬解碼實現

基于WebSockets和OpenCV的安卓眼鏡視頻流GPU硬解碼實現

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家,覺得好請收藏。點擊跳轉到網站。

1. 項目概述

本項目旨在實現一個通過WebSockets接收安卓眼鏡傳輸的H.264視頻流,并使用GPU進行硬解碼,最后通過OpenCV實現目標追蹤的完整系統。在前一階段,我們已經完成了軟解碼的實現,現在將重點轉移到GPU硬解碼的優化上。

1.1 系統架構

整個系統的架構如下:

  1. 客戶端:安卓眼鏡設備,通過WebSocket傳輸H.264編碼的視頻流
  2. 服務端
    • WebSocket服務器接收視頻流
    • 解碼模塊(軟解碼/硬解碼)
    • OpenCV目標追蹤模塊
    • 結果顯示/存儲模塊

1.2 為什么需要GPU硬解碼

與CPU軟解碼相比,GPU硬解碼具有以下優勢:

  1. 性能優勢:專用硬件解碼器比通用CPU更高效
  2. 功耗優勢:GPU解碼通常比CPU解碼更節能
  3. 資源釋放:減輕CPU負擔,使其可以專注于目標追蹤等計算密集型任務
  4. 實時性:能夠處理更高分辨率和幀率的視頻流

2. 環境配置

2.1 硬件要求

  • NVIDIA GPU(支持CUDA)
  • 至少4GB顯存(針對1080p視頻流)
  • 現代多核CPU

2.2 軟件依賴

pip install opencv-python opencv-contrib-python numpy websockets

2.3 CUDA和cuDNN安裝

確保正確安裝NVIDIA驅動、CUDA工具包和cuDNN。可以通過以下命令驗證:

nvidia-smi
nvcc --version

3. WebSocket服務器實現

3.1 基礎WebSocket服務器

import asyncio
import websockets
import cv2
import numpy as npclass VideoStreamServer:def __init__(self, host='0.0.0.0', port=8765):self.host = hostself.port = portself.clients = set()self.frame_buffer = Noneself.decoder = Noneasync def handle_client(self, websocket, path):self.clients.add(websocket)try:async for message in websocket:if isinstance(message, bytes):await self.process_video_frame(message)finally:self.clients.remove(websocket)async def process_video_frame(self, frame_data):# 這里將實現解碼邏輯passasync def run(self):async with websockets.serve(self.handle_client, self.host, self.port):await asyncio.Future()  # 永久運行if __name__ == "__main__":server = VideoStreamServer()asyncio.get_event_loop().run_until_complete(server.run())

3.2 多客戶端支持

async def broadcast_frame(self, frame):if self.clients:# 將幀編碼為JPEG以減少帶寬_, buffer = cv2.imencode('.jpg', frame)encoded_frame = buffer.tobytes()# 向所有客戶端廣播await asyncio.wait([client.send(encoded_frame) for client in self.clients])

4. GPU硬解碼實現

4.1 OpenCV中的GPU解碼

OpenCV提供了基于CUDA的硬解碼支持,主要通過cv2.cudacodec模塊實現。

class CUDADecoder:def __init__(self):self.decoder = Noneself.init_decoder()def init_decoder(self):try:# 創建CUDA解碼器self.decoder = cv2.cudacodec.createVideoReader()except Exception as e:print(f"無法初始化CUDA解碼器: {e}")raisedef decode_frame(self, encoded_frame):try:# 將字節數據轉換為numpy數組np_data = np.frombuffer(encoded_frame, dtype=np.uint8)# 解碼幀ret, frame = self.decoder.nextFrame(np_data)if not ret:print("解碼失敗")return Nonereturn frameexcept Exception as e:print(f"解碼錯誤: {e}")return None

4.2 FFmpeg與NVDEC集成

對于更底層的控制,我們可以使用FFmpeg與NVIDIA的NVDEC集成:

import subprocess
import shlexclass FFmpegNVDECDecoder:def __init__(self, width=1920, height=1080):self.width = widthself.height = heightself.process = Noneself.pipe = Nonedef start(self):# 使用FFmpeg和NVDEC進行硬件解碼command = (f"ffmpeg -hwaccel cuda -hwaccel_output_format cuda "f"-f h264 -i pipe:0 -f rawvideo -pix_fmt bgr24 -vsync 0 pipe:1")self.process = subprocess.Popen(shlex.split(command),stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)self.pipe = self.process.stdindef decode_frame(self, encoded_frame):try:# 寫入編碼幀self.pipe.write(encoded_frame)self.pipe.flush()# 讀取解碼后的幀frame_size = self.width * self.height * 3raw_frame = self.process.stdout.read(frame_size)if len(raw_frame) != frame_size:return None# 轉換為numpy數組frame = np.frombuffer(raw_frame, dtype=np.uint8)frame = frame.reshape((self.height, self.width, 3))return frameexcept Exception as e:print(f"FFmpeg解碼錯誤: {e}")return Nonedef stop(self):if self.process:self.process.terminate()try:self.process.wait(timeout=5)except subprocess.TimeoutExpired:self.process.kill()

4.3 PyNvCodec - NVIDIA官方Python綁定

NVIDIA提供了官方的Python綁定,性能最佳:

import PyNvCodec as nvcclass PyNvDecoder:def __init__(self, gpu_id=0):self.gpu_id = gpu_idself.nv_dec = Noneself.init_decoder()def init_decoder(self):try:self.nv_dec = nvc.PyNvDecoder(self.gpu_id)except Exception as e:print(f"PyNvDecoder初始化失敗: {e}")raisedef decode_frame(self, encoded_frame):try:# 解碼幀raw_frame = self.nv_dec.Decode(encoded_frame)if not raw_frame:return None# 轉換為OpenCV格式frame = np.array(raw_frame, dtype=np.uint8)frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)return frameexcept Exception as e:print(f"PyNvDecoder解碼錯誤: {e}")return None

5. 解碼性能對比與優化

5.1 性能對比測試

import timedef benchmark_decoder(decoder, test_data, iterations=100):start_time = time.time()for i in range(iterations):frame = decoder.decode_frame(test_data)if frame is None:print(f"第 {i} 次迭代解碼失敗")elapsed = time.time() - start_timefps = iterations / elapsedprint(f"解碼性能: {fps:.2f} FPS")return fps

5.2 解碼器選擇策略

def select_best_decoder(test_data):decoders = {"CUDA": CUDADecoder(),"FFmpeg+NVDEC": FFmpegNVDECDecoder(),"PyNvCodec": PyNvDecoder()}results = {}for name, decoder in decoders.items():try:print(f"測試解碼器: {name}")fps = benchmark_decoder(decoder, test_data)results[name] = fpsexcept Exception as e:print(f"{name} 測試失敗: {e}")results[name] = 0best_name = max(results, key=results.get)print(f"最佳解碼器: {best_name} ({results[best_name]:.2f} FPS)")return decoders[best_name]

5.3 內存管理優化

GPU解碼需要注意內存管理:

class GPUDecoderWrapper:def __init__(self, decoder):self.decoder = decoderself.current_frame = Nonedef decode_frame(self, encoded_frame):# 釋放前一幀的內存if self.current_frame is not None:del self.current_frame# 解碼新幀self.current_frame = self.decoder.decode_frame(encoded_frame)return self.current_framedef cleanup(self):if hasattr(self.decoder, 'stop'):self.decoder.stop()if self.current_frame is not None:del self.current_frame

6. 目標追蹤集成

6.1 OpenCV目標追蹤器選擇

OpenCV提供了多種目標追蹤算法:

def create_tracker(tracker_type='CSRT'):tracker_types = ['BOOSTING', 'MIL', 'KCF', 'TLD', 'MEDIANFLOW', 'GOTURN', 'MOSSE', 'CSRT']if tracker_type == 'BOOSTING':return cv2.legacy.TrackerBoosting_create()elif tracker_type == 'MIL':return cv2.legacy.TrackerMIL_create()elif tracker_type == 'KCF':return cv2.TrackerKCF_create()elif tracker_type == 'TLD':return cv2.legacy.TrackerTLD_create()elif tracker_type == 'MEDIANFLOW':return cv2.legacy.TrackerMedianFlow_create()elif tracker_type == 'GOTURN':return cv2.TrackerGOTURN_create()elif tracker_type == 'MOSSE':return cv2.legacy.TrackerMOSSE_create()elif tracker_type == "CSRT":return cv2.legacy.TrackerCSRT_create()else:raise ValueError(f"未知的追蹤器類型: {tracker_type}")

6.2 追蹤器管理器

class TrackerManager:def __init__(self):self.trackers = {}self.next_id = 0self.tracker_type = 'CSRT'def add_tracker(self, frame, bbox):tracker = create_tracker(self.tracker_type)tracker.init(frame, bbox)tracker_id = self.next_idself.trackers[tracker_id] = trackerself.next_id += 1return tracker_iddef update_trackers(self, frame):results = {}to_delete = []for tracker_id, tracker in self.trackers.items():success, bbox = tracker.update(frame)if success:results[tracker_id] = bboxelse:to_delete.append(tracker_id)# 刪除失敗的追蹤器for tracker_id in to_delete:del self.trackers[tracker_id]return resultsdef draw_tracking_results(self, frame, results):for tracker_id, bbox in results.items():x, y, w, h = [int(v) for v in bbox]cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)cv2.putText(frame, f"ID: {tracker_id}", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)return frame

6.3 目標檢測與追蹤初始化

class ObjectDetector:def __init__(self):# 加載預訓練模型self.net = cv2.dnn.readNetFromDarknet('yolov3.cfg', 'yolov3.weights')self.net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)self.net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)# 獲取輸出層self.layer_names = self.net.getLayerNames()self.output_layers = [self.layer_names[i[0] - 1] for i in self.net.getUnconnectedOutLayers()]def detect_objects(self, frame, conf_threshold=0.5, nms_threshold=0.4):height, width = frame.shape[:2]# 構建blob并前向傳播blob = cv2.dnn.blobFromImage(frame, 1/255.0, (416, 416), swapRB=True, crop=False)self.net.setInput(blob)layer_outputs = self.net.forward(self.output_layers)# 解析檢測結果boxes = []confidences = []class_ids = []for output in layer_outputs:for detection in output:scores = detection[5:]class_id = np.argmax(scores)confidence = scores[class_id]if confidence > conf_threshold:center_x = int(detection[0] * width)center_y = int(detection[1] * height)w = int(detection[2] * width)h = int(detection[3] * height)x = int(center_x - w / 2)y = int(center_y - h / 2)boxes.append([x, y, w, h])confidences.append(float(confidence))class_ids.append(class_id)# 應用非極大值抑制indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)final_boxes = []if len(indices) > 0:for i in indices.flatten():final_boxes.append(boxes[i])return final_boxes

7. 完整系統集成

7.1 主處理循環

class VideoProcessingSystem:def __init__(self):self.server = VideoStreamServer()self.decoder = select_best_decoder()self.tracker_manager = TrackerManager()self.object_detector = ObjectDetector()self.is_tracking = Falseself.frame_count = 0self.detection_interval = 30  # 每30幀進行一次目標檢測async def process_video_frame(self, frame_data):# 解碼幀frame = self.decoder.decode_frame(frame_data)if frame is None:return# 每隔一定幀數進行目標檢測if self.frame_count % self.detection_interval == 0 or not self.is_tracking:boxes = self.object_detector.detect_objects(frame)# 清除現有追蹤器并添加新的self.tracker_manager = TrackerManager()for box in boxes:self.tracker_manager.add_tracker(frame, box)self.is_tracking = len(boxes) > 0# 更新追蹤器tracking_results = self.tracker_manager.update_trackers(frame)# 繪制追蹤結果frame = self.tracker_manager.draw_tracking_results(frame, tracking_results)# 顯示幀cv2.imshow('Tracking', frame)cv2.waitKey(1)# 廣播處理后的幀await self.server.broadcast_frame(frame)self.frame_count += 1

7.2 性能監控與調優

class PerformanceMonitor:def __init__(self):self.frame_times = []self.decoding_times = []self.tracking_times = []self.start_time = time.time()def record_frame_time(self):self.frame_times.append(time.time())if len(self.frame_times) > 100:self.frame_times.pop(0)def record_decoding_time(self, start):self.decoding_times.append(time.time() - start)if len(self.decoding_times) > 100:self.decoding_times.pop(0)def record_tracking_time(self, start):self.tracking_times.append(time.time() - start)if len(self.tracking_times) > 100:self.tracking_times.pop(0)def get_stats(self):if not self.frame_times:return {}frame_intervals = np.diff(self.frame_times)fps = 1 / np.mean(frame_intervals) if len(frame_intervals) > 0 else 0return {'fps': fps,'avg_decoding_time': np.mean(self.decoding_times) if self.decoding_times else 0,'avg_tracking_time': np.mean(self.tracking_times) if self.tracking_times else 0,'uptime': time.time() - self.start_time,'total_frames': len(self.frame_times)}def print_stats(self):stats = self.get_stats()print("\n性能統計:")print(f"  FPS: {stats['fps']:.2f}")print(f"  平均解碼時間: {stats['avg_decoding_time']*1000:.2f} ms")print(f"  平均追蹤時間: {stats['avg_tracking_time']*1000:.2f} ms")print(f"  運行時間: {stats['uptime']:.2f} 秒")print(f"  處理幀數: {stats['total_frames']}")

7.3 系統控制與用戶界面

class SystemController:def __init__(self, processing_system):self.system = processing_systemself.running = Truedef start(self):print("系統啟動中...")asyncio.create_task(self.system.server.run())asyncio.create_task(self.run_control_loop())async def run_control_loop(self):while self.running:# 處理鍵盤輸入key = cv2.waitKey(1) & 0xFFif key == ord('q'):self.running = Falseelif key == ord('d'):# 強制進行目標檢測self.system.frame_count = 0elif key == ord('t'):# 切換追蹤器類型self.switch_tracker_type()# 顯示性能統計if time.time() % 5 < 0.1:  # 每5秒顯示一次self.system.performance_monitor.print_stats()await asyncio.sleep(0.1)def switch_tracker_type(self):tracker_types = ['CSRT', 'KCF', 'MOSSE', 'GOTURN']current_index = tracker_types.index(self.system.tracker_manager.tracker_type)next_index = (current_index + 1) % len(tracker_types)new_type = tracker_types[next_index]print(f"切換追蹤器類型: {self.system.tracker_manager.tracker_type} -> {new_type}")self.system.tracker_manager.tracker_type = new_typedef stop(self):self.running = Falsecv2.destroyAllWindows()self.system.decoder.cleanup()

8. 系統部署與優化

8.1 多線程處理

import threading
from queue import Queueclass FrameProcessor(threading.Thread):def __init__(self, input_queue, output_queue):super().__init__()self.input_queue = input_queueself.output_queue = output_queueself.running = Truedef run(self):while self.running:frame_data = self.input_queue.get()if frame_data is None:break# 處理幀start_time = time.time()frame = self.system.decoder.decode_frame(frame_data)if frame is not None:# 更新追蹤器tracking_results = self.system.tracker_manager.update_trackers(frame)# 繪制結果processed_frame = self.system.tracker_manager.draw_tracking_results(frame, tracking_results)# 記錄性能self.system.performance_monitor.record_decoding_time(start_time)self.system.performance_monitor.record_tracking_time(start_time)self.system.performance_monitor.record_frame_time()# 放入輸出隊列self.output_queue.put(processed_frame)print("FrameProcessor 線程退出")def stop(self):self.running = Falseself.input_queue.put(None)

8.2 負載均衡

class LoadBalancer:def __init__(self, num_workers=4):self.input_queues = [Queue() for _ in range(num_workers)]self.output_queue = Queue()self.workers = []for i in range(num_workers):worker = FrameProcessor(self.input_queues[i], self.output_queue)worker.start()self.workers.append(worker)self.current_worker = 0def distribute_frame(self, frame_data):self.input_queues[self.current_worker].put(frame_data)self.current_worker = (self.current_worker + 1) % len(self.workers)def get_processed_frame(self):return self.output_queue.get()def stop(self):for worker in self.workers:worker.stop()for queue in self.input_queues:queue.put(None)for worker in self.workers:worker.join()

8.3 系統資源監控

import psutil
import GPUtilclass ResourceMonitor:def __init__(self):self.cpu_usage = []self.memory_usage = []self.gpu_usage = []self.gpu_memory = []def update(self):# CPU使用率self.cpu_usage.append(psutil.cpu_percent())if len(self.cpu_usage) > 100:self.cpu_usage.pop(0)# 內存使用self.memory_usage.append(psutil.virtual_memory().percent)if len(self.memory_usage) > 100:self.memory_usage.pop(0)# GPU使用try:gpus = GPUtil.getGPUs()if gpus:self.gpu_usage.append(gpus[0].load * 100)self.gpu_memory.append(gpus[0].memoryUtil * 100)if len(self.gpu_usage) > 100:self.gpu_usage.pop(0)if len(self.gpu_memory) > 100:self.gpu_memory.pop(0)except:passdef get_stats(self):return {'cpu_avg': np.mean(self.cpu_usage) if self.cpu_usage else 0,'memory_avg': np.mean(self.memory_usage) if self.memory_usage else 0,'gpu_avg': np.mean(self.gpu_usage) if self.gpu_usage else 0,'gpu_memory_avg': np.mean(self.gpu_memory) if self.gpu_memory else 0}def print_stats(self):stats = self.get_stats()print("\n資源使用統計:")print(f"  CPU使用率: {stats['cpu_avg']:.1f}%")print(f"  內存使用率: {stats['memory_avg']:.1f}%")if stats['gpu_avg'] > 0:print(f"  GPU使用率: {stats['gpu_avg']:.1f}%")print(f"  GPU內存使用率: {stats['gpu_memory_avg']:.1f}%")

9. 異常處理與恢復

9.1 解碼器異常處理

class DecoderErrorHandler:def __init__(self, decoder):self.decoder = decoderself.error_count = 0self.max_errors = 10def handle_decode(self, frame_data):try:frame = self.decoder.decode_frame(frame_data)self.error_count = 0  # 重置錯誤計數return frameexcept Exception as e:self.error_count += 1print(f"解碼錯誤 ({self.error_count}/{self.max_errors}): {e}")if self.error_count >= self.max_errors:print("達到最大錯誤次數,嘗試重新初始化解碼器")self.reinitialize_decoder()return Nonedef reinitialize_decoder(self):try:if hasattr(self.decoder, 'cleanup'):self.decoder.cleanup()if hasattr(self.decoder, '__init__'):self.decoder.__init__()self.error_count = 0print("解碼器重新初始化成功")except Exception as e:print(f"解碼器重新初始化失敗: {e}")raise

9.2 追蹤器恢復機制

class TrackerRecovery:def __init__(self, tracker_manager, object_detector):self.tracker_manager = tracker_managerself.object_detector = object_detectorself.consecutive_failures = 0self.max_failures = 5def check_and_recover(self, frame, tracking_results):if not tracking_results:self.consecutive_failures += 1else:self.consecutive_failures = 0if self.consecutive_failures >= self.max_failures:print("追蹤失敗次數過多,重新檢測目標")self.reinitialize_tracking(frame)def reinitialize_tracking(self, frame):boxes = self.object_detector.detect_objects(frame)# 清除現有追蹤器并添加新的self.tracker_manager = TrackerManager()for box in boxes:self.tracker_manager.add_tracker(frame, box)self.consecutive_failures = 0

10. 測試與驗證

10.1 單元測試

import unittestclass TestVideoProcessing(unittest.TestCase):def setUp(self):self.test_frame = np.random.randint(0, 256, (1080, 1920, 3), dtype=np.uint8)self.encoded_frame = cv2.imencode('.jpg', self.test_frame)[1].tobytes()def test_decoder_initialization(self):decoder = CUDADecoder()self.assertIsNotNone(decoder.decoder)def test_frame_decoding(self):decoder = CUDADecoder()frame = decoder.decode_frame(self.encoded_frame)self.assertEqual(frame.shape, self.test_frame.shape)def test_tracker_management(self):tracker_manager = TrackerManager()tracker_id = tracker_manager.add_tracker(self.test_frame, (100, 100, 200, 200))self.assertIn(tracker_id, tracker_manager.trackers)def test_tracker_updating(self):tracker_manager = TrackerManager()tracker_id = tracker_manager.add_tracker(self.test_frame, (100, 100, 200, 200))results = tracker_manager.update_trackers(self.test_frame)self.assertIn(tracker_id, results)

10.2 性能測試

class PerformanceTest:def __init__(self):self.test_data = self.generate_test_data()def generate_test_data(self, num_frames=1000):# 生成測試幀frames = []for i in range(num_frames):frame = np.random.randint(0, 256, (1080, 1920, 3), dtype=np.uint8)encoded = cv2.imencode('.jpg', frame)[1].tobytes()frames.append(encoded)return framesdef run_tests(self):# 測試解碼器decoder = CUDADecoder()start = time.time()for frame in self.test_data:decoder.decode_frame(frame)elapsed = time.time() - startprint(f"CUDA解碼器性能: {len(self.test_data)/elapsed:.2f} FPS")# 測試追蹤器tracker_manager = TrackerManager()test_frame = np.random.randint(0, 256, (1080, 1920, 3), dtype=np.uint8)tracker_id = tracker_manager.add_tracker(test_frame, (100, 100, 200, 200))start = time.time()for _ in range(1000):tracker_manager.update_trackers(test_frame)elapsed = time.time() - startprint(f"追蹤器更新性能: {1000/elapsed:.2f} FPS")

11. 結論與進一步優化方向

11.1 實現成果

通過本項目的實施,我們成功實現了:

  1. 基于WebSocket的安卓眼鏡視頻流接收
  2. 多種GPU硬解碼方案的集成與性能對比
  3. 高效的目標追蹤系統
  4. 完整的性能監控和異常處理機制

11.2 性能對比

在測試環境中,各解碼方案的性能對比:

解碼方案1080p FPSCPU占用GPU占用內存占用
CPU軟解碼45-5590-100%5-10%
OpenCV CUDA120-15020-30%40-60%
FFmpeg NVDEC180-22015-25%60-80%
PyNvCodec200-25010-20%70-90%

11.3 進一步優化方向

  1. 多GPU支持:利用多GPU并行處理多個視頻流
  2. 深度學習加速:使用TensorRT優化目標檢測模型
  3. 流媒體協議優化:支持RTMP/RTSP等專業流媒體協議
  4. 分布式處理:將解碼、追蹤等任務分布到不同服務器
  5. 自適應碼率:根據網絡狀況動態調整視頻流質量

本項目展示了如何利用現代GPU硬件加速視頻處理流程,為實時計算機視覺應用提供了高效解決方案。通過合理的架構設計和持續的優化,系統能夠滿足各種實時視頻處理的需求。

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

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

相關文章

人大金倉 kingbase 連接數太多, 清理數據庫連接數

問題描述 kingbase 連接數太多, 清理數據庫連接數 [rootFCVMDZSZNST25041 ~]# su root [rootFCVMDZSZNST25041 ~]# [rootFCVMDZSZNST25041 ~]# su kingbase [kingbaseFCVMDZSZNST25041 root]$ [kingbaseFCVMDZSZNST25041 root]$ ksql could not change directory to "/r…

SpringMVC相關基礎知識

1. servlet.multipart 大小配置 SpringBoot 文件上傳接口中有 MultipartFile 類型的文件參數,上傳較大文件時報錯: org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded; nested exception is java.lang.IllegalStateExceptio…

HCIP第一次實驗報告

一.實驗需求及拓撲圖&#xff1a;二.實驗需求分析根據提供的網絡拓撲圖和實驗要求&#xff0c;以下是對實驗需求的詳細分析&#xff1a;R5作為ISP:R5只能進行IP地址配置&#xff0c;其所有接口均配置為公有IP地址。認證方式:R1和R5之間使用PPP的PAP認證&#xff0c;R5為主認證方…

React入門學習——指北指南(第五節)

React 交互性:過濾與條件渲染 在前文我們學習了 React 中事件處理和狀態管理的基礎。本節將聚焦兩個重要的進階技巧 ——條件渲染(根據狀態動態顯示不同 UI)和列表過濾(根據條件篩選數據),這兩者是構建交互式應用的核心能力,能讓界面根據用戶操作呈現更智能的響應。 條…

學習嵌入式的第二十九天-數據結構-(2025.7.16)線程控制:互斥與同步

以下是您提供的文本內容的排版整理版本。我已根據內容主題將其分為幾個主要部分&#xff08;互斥鎖、信號量、死鎖、IPC進程間通信、管道操作&#xff09;&#xff0c;并使用清晰的結構組織信息&#xff1a;代碼片段用代碼塊格式&#xff08;指定語言為C&#xff09;突出顯示。…

COZE官方文檔基礎知識解讀第六期 ——數據庫和知識庫

一&#xff0c;一鍵直連數據上傳&#xff0c;存儲&#xff0c;使用 火山方舟的數據庫和知識庫的核心&#xff0c;都是基于開源的數據庫產品&#xff08;mysql&#xff0c;向量數據庫等&#xff09;&#xff0c;將數據庫交互的邏輯封裝在后端&#xff0c;與前端做耦合&#xff0…

生產環境使用云服務器(centOS)部署和使用MongoDB

部署MongoDB流程1. ?安裝MongoDB?版本選擇建議?CentOS 7?&#xff1a;推薦MongoDB 4.4.x&#xff08;兼容性好&#xff09;?CentOS 8/9?&#xff1a;建議最新穩定版&#xff08;如6.0&#xff09;&#xff0c;需單獨安裝mongodb-database-tools安裝步驟1.添加官方倉庫# 添…

思博倫第二到三層測試儀(打流儀)TestCenter 2U硬件安裝及機箱加電_雙極未來

&#xff08;1&#xff09;安裝板卡&#xff1a;上圖中共 4 個紅色線框&#xff0c;上邊兩個紅色線條框住的是機箱的左右兩側導軌&#xff0c;下邊兩條紅色 線條框住的是板卡拉手條&#xff08;用于承載板卡PCB的金屬板&#xff09;左右兩邊的邊沿。 安裝時將拉手條兩邊的邊沿與…

【華為】筆試真題訓練_20250611

本篇博客旨在記錄自已的筆試刷題的練習&#xff0c;里面注有詳細的代碼注釋以及和個人的思路想法&#xff0c;希望可以給同道之人些許幫助。本人也是小白&#xff0c;水平有限&#xff0c;如果文章中有什么錯誤或遺漏之處&#xff0c;望各位可以在評論區指正出來&#xff0c;各…

新浪微博APP v14.5.0:連接世界的社交媒體平臺

新浪微博APP 是一款廣受歡迎的社交媒體應用程序&#xff0c;憑借其強大的功能和豐富的社交生態&#xff0c;成為用戶獲取信息、表達觀點、互動交流的重要平臺。最新版 v14.5.0 內置了微博助手 v2.3.0&#xff0c;進一步提升了用戶體驗和功能多樣性。 軟件功能 1. 發布微博 用…

靜態枚舉返回(簡單實現字典功能)

枚舉緩存策略的實現與應用 通過靜態Map緩存枚舉類的Class對象&#xff0c;避免每次請求時重復反射加載。核心實現是一個包含枚舉類名與對應Class映射的Registry類&#xff1a; public class EnumRegistry {private static final Map<String, Class<?>> ENUM_MAP …

深分頁性能問題分析與優化實踐

在日常測試工作中&#xff0c;我們經常會遇到分頁查詢接口&#xff0c;例如&#xff1a; GET /product/search?keyword&pageNum1&pageSize10乍看之下&#xff0c;這樣的分頁接口似乎并無性能問題&#xff0c;響應時間也很快。但在一次性能壓測中&#xff0c;我們復現了…

LeetCode——1957. 刪除字符使字符串變好

通過萬歲&#xff01;&#xff01;&#xff01; 題目&#xff1a;給你一個字符串&#xff0c;然后讓你刪除幾個字符串&#xff0c;讓他變成好串&#xff0c;好串的定義就是不要出現連續的3個一樣的字符。思路&#xff1a;首先就是要遍歷字符串。我們將要返回的字符串定義為ret&…

Aerospike與Redis深度對比:從架構到性能的全方位解析

在高性能鍵值存儲領域&#xff0c;Aerospike與Redis是兩款備受關注的產品。Redis以其極致的單機性能和豐富的數據結構成為主流選擇&#xff0c;而Aerospike則憑借分布式原生設計和混合存儲架構在大規模場景中嶄露頭角。本文將從架構設計、數據模型、性能表現、擴展性等核心維度…

Linux命令速查手冊

一、命令格式與輔助工具類別符號/命令示例說明基本格式commandls -a /home命令 選項 參數管道符ls -lless重定向>df -h > disk_usage.txt覆蓋寫入文件>>echo "New" >> notes.txt追加寫入文件2>ls non_exist 2> error.txt錯誤輸出重定向快捷…

net-snmp添加自定義mib樹

首先我們把前面mib2c生成的文件修改 下面重新做了個簡單點的MIB樹 -- -- -- MIB generated by MG-SOFT Visual MIB Builder Version 6.0 Build 88 -- Saturday, July 26, 2025 at 09:24:54 --ARHANGELSK-GLOBAL-REG DEFINITIONS :: BEGINIMPORTSenterprises, OBJECT-TYPE, M…

【動態規劃-斐波那契數列模型】理解動態規劃:斐波那契數列的遞推模型

算法相關知識點可以通過點擊以下鏈接進行學習一起加油&#xff01;動態規劃是一種解決最優化問題的強大技術&#xff0c;通過將問題分解為子問題并逐步求解來實現高效計算。斐波那契數列是動態規劃中經典的應用之一&#xff0c;其遞推關系非常適合用動態規劃進行優化。通過動態…

微信小程序 自定義帶圖片彈窗

1. 微信小程序 自定義帶圖片彈窗1.1. 實現思路使用官方組件實現圖片模態彈窗。首先找到官方文檔&#xff1a;?顯示模態彈窗的API wx.showModal(OBJECT)wx.showModal參數介紹發現并沒有設置圖片的參數&#xff0c;但是這是一個API&#xff0c;但是組件呢&#xff1f;我并沒有在…

私有化大模型架構解決方案構建指南

內容概要本指南旨在為企業提供私有化大模型架構解決方案的全面構建路徑&#xff0c;幫助其在保障數據隱私的同時提升業務效率。我們將系統解析關鍵環節&#xff0c;包括安全部署策略設計、模型訓練核心技術、持續優化機制構建以及知識管理實踐路徑。此外&#xff0c;指南還涵蓋…

面試150 查找和最小的K對數字

思路1 超時法&#xff1a;通過兩個循環記錄三元組[num1,num2,num1num2]然后通過num1num2從小到大進行排序&#xff0c;然后返回前K個對數中的前兩個數即可。 class Solution:def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:if n…