# Day 19 - 通信传输优化 **日期**: 2025-12-23 **主题**: 服务器端数据处理逻辑优化,解决传输拥堵问题 --- ## 问题分析 用户反馈室外测试时传输拥堵,经分析确认: - 2.4GHz 热点带宽不是瓶颈(需求 ~1.6 Mbps,实测 5-10 Mbps) - 服务器配置强劲(双 E5-2680 v4 + 双 RTX 3090) - **真正问题**:服务器端每帧都执行无意义的解码-编码循环 --- ## 瓶颈识别 ### 之前的代码逻辑 ```python # 每帧都解码,无论是否需要处理 arr = np.frombuffer(data, dtype=np.uint8) bgr = cv2.imdecode(arr, cv2.IMREAD_COLOR) # CPU 密集! # 即使不需要处理,也重新编码再发送 ok, enc = cv2.imencode(".jpg", bgr, ...) # 又是 CPU 密集! await _broadcast_to_viewers(enc.tobytes()) ``` **问题**:客户端发送的 `data` 本身就是 JPEG,完全不需要解码再编码! --- ## 优化方案 ### 1. 零拷贝直传 对于不需要处理的模式(CHAT/IDLE/ITEM_SEARCH),直接转发原始 JPEG: ```diff - if bgr is not None: - ok, enc = cv2.imencode(".jpg", bgr, ...) - await _broadcast_to_viewers(enc.tobytes()) + await _broadcast_to_viewers(data) # 直接转发原始 JPEG ``` ### 2. 延迟解码 只在真正需要导航处理时才执行 `cv2.imdecode`: ```diff + needs_processing = (orchestrator and not yolomedia_running) + bgr = None # 延迟初始化 + if needs_processing: + current_state = orchestrator.get_state() + if current_state in ("ITEM_SEARCH", "CHAT", "IDLE"): + await _broadcast_to_viewers(data) # 零拷贝 + continue + # 只有导航模式才解码 + bgr = turbo_decode(data) ``` ### 3. TurboJPEG 加速编解码 使用 **TurboJPEG**(基于 libjpeg-turbo 的 SIMD 优化库)替换 `cv2.imencode`/`cv2.imdecode`: ```python # 安装 pip install PyTurboJPEG # 使用(带回退逻辑) from turbojpeg import TurboJPEG _turbo_jpeg = TurboJPEG() def turbo_decode(jpeg_bytes): return _turbo_jpeg.decode(jpeg_bytes) # 2-3x faster def turbo_encode(bgr_image, quality=80): return _turbo_jpeg.encode(bgr_image, quality=quality) # 2-3x faster ``` **速度对比**: | 操作 | cv2 | TurboJPEG | 提升 | |------|-----|-----------|------| | 解码 640x480 | ~5ms | ~2ms | **2.5x** | | 编码 640x480 | ~8ms | ~3ms | **2.7x** | ### 4. 导航结果 JPEG 缓存 导航处理后的标注图像只在有新结果时编码一次,后续帧复用缓存: ```python _nav_last_result_jpeg = None # 缓存编码后的 JPEG # 新结果时编码并缓存 if res.annotated_image is not None: _nav_last_result_jpeg = turbo_encode(res.annotated_image, quality=80) # 广播时直接使用缓存 await _broadcast_to_viewers(_nav_last_result_jpeg) ``` --- ## 修改文件 | 文件 | 修改内容 | |------|----------| | `app_main.py` | TurboJPEG 导入、turbo_decode/encode 函数、零拷贝直传、延迟解码、JPEG 缓存 | | `requirements.txt` | 添加 PyTurboJPEG>=1.7.0 | | `.env` | GPU 1 配置、性能参数优化 | --- ## 预期效果 | 场景 | 之前 | 之后 | 优化幅度 | |------|------|------|---------| | CHAT/IDLE 模式 | imdecode + imencode | 直接转发 | **-100%** | | ITEM_SEARCH 模式 | imdecode + imencode | 直接转发 | **-100%** | | 导航模式(新结果) | imdecode + imencode | turbo_decode + turbo_encode(一次) | **2-3x** | | 导航模式(复用结果) | imdecode + imencode | 直接转发缓存 | **-100%** | **综合效果**: - 非导航场景:CPU 开销降低 **90%+** - 导航场景(8fps,YOLO 约 2fps):编码次数从 8 次/秒 降至 **2 次/秒** - 编解码速度:提升 **2-3 倍** --- ## 部署步骤 ```bash # 服务器端 cd OpenAIglasses_for_Navigation pip install PyTurboJPEG python app_main.py # 启动后应看到日志: # [INIT] TurboJPEG 加载成功,JPEG 编解码将使用加速版本 ``` --- ## 验证结果 (2025-12-23 下午) - [x] 服务器端部署后测试 - [x] 导航模式功能正常 - [x] 所有模式切换正常 - [x] nvidia-smi 确认使用 GPU 1 - [ ] 室外 4G 热点实测传输流畅度(待测) --- ## 新问题诊断 ### 问题现象 测试盲道导航时发现: 1. **GPU 利用率仅 7%** - 远低于预期 2. **Python 进程占用 120% CPU** - 但服务器总 CPU 仅 3%(56 核利用率极低) 3. **帧处理 FPS 仅 3-4 帧** - 画面卡顿严重 4. **TTS 语音有时不播放** - 音频 WebSocket 断开导致缓冲 ### 根本原因:Python GIL 瓶颈 ``` ┌─────────────────────────────────────────────────────────────┐ │ Python 进程 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ GIL (全局解释器锁) │ │ │ │ 同一时刻只有一个线程执行 Python 代码 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ Thread 1 (frame_proc-0) ──▶ 执行中 │ │ Thread 2 (frame_proc-1) ──▶ 等待 GIL │ │ Thread 3 (frame_proc-2) ──▶ 等待 GIL │ │ │ │ 结果:3 个线程实际只能用 1 个 CPU 核心 │ └─────────────────────────────────────────────────────────────┘ ``` **关键代码位置**: ```python # app_main.py 第 237 行 frame_processing_executor = ThreadPoolExecutor(max_workers=3, ...) ``` `ThreadPoolExecutor` 受 GIL 限制,无法真正并行化 CPU 密集型任务。 --- ## 遗留问题与解决方案 ### 问题 1:CPU 单线程瓶颈 **状态**:❌ 未解决 **解决方案**:使用 **PyNvJpeg** 将 JPEG 编解码移到 GPU ```bash pip install pynvjpeg ``` **实施步骤**: 1. 创建 `gpu_jpeg.py` 模块 2. 修改 `app_main.py` 替换 turbo_decode/turbo_encode ### 问题 2:TTS 语音不播放 **状态**:❌ 未解决 **现象**:`[TTS->WS] Buffering TTS audio, will send when reconnected` **原因**:音频 WebSocket 断开 ### 问题 3:画面卡顿/滞后 **状态**:⚠️ 待问题 1 解决后验证 --- ## 明日开发计划 1. **安装 PyNvJpeg**:`pip install pynvjpeg` 2. **创建 gpu_jpeg.py 模块** 3. **修改 app_main.py 使用 GPU JPEG** 4. **性能验证**:`watch -n 1 nvidia-smi` 5. **验证 TTS 播放问题** --- ## 服务器配置 | 组件 | 配置 | |------|------| | CPU | 2× Intel Xeon E5-2680 v4 (56 线程) | | 内存 | 192 GB DDR4 | | GPU | 2× NVIDIA RTX 3090 (24 GB) |