Files
Docs/DevLogs/Day19.md
2025-12-31 16:18:28 +08:00

7.2 KiB
Raw Permalink Blame History

Day 19 - 通信传输优化

日期: 2025-12-23
主题: 服务器端数据处理逻辑优化,解决传输拥堵问题


问题分析

用户反馈室外测试时传输拥堵,经分析确认:

  • 2.4GHz 热点带宽不是瓶颈(需求 ~1.6 Mbps实测 5-10 Mbps
  • 服务器配置强劲(双 E5-2680 v4 + 双 RTX 3090
  • 真正问题:服务器端每帧都执行无意义的解码-编码循环

瓶颈识别

之前的代码逻辑

# 每帧都解码,无论是否需要处理
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

- 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

+ 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

# 安装
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 缓存

导航处理后的标注图像只在有新结果时编码一次,后续帧复用缓存:

_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%+
  • 导航场景8fpsYOLO 约 2fps编码次数从 8 次/秒 降至 2 次/秒
  • 编解码速度:提升 2-3 倍

部署步骤

# 服务器端
cd OpenAIglasses_for_Navigation
pip install PyTurboJPEG
python app_main.py

# 启动后应看到日志:
# [INIT] TurboJPEG 加载成功JPEG 编解码将使用加速版本

验证结果 (2025-12-23 下午)

  • 服务器端部署后测试
  • 导航模式功能正常
  • 所有模式切换正常
  • 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 核心                      │
└─────────────────────────────────────────────────────────────┘

关键代码位置

# app_main.py 第 237 行
frame_processing_executor = ThreadPoolExecutor(max_workers=3, ...)

ThreadPoolExecutor 受 GIL 限制,无法真正并行化 CPU 密集型任务。


遗留问题与解决方案

问题 1CPU 单线程瓶颈

状态 未解决

解决方案:使用 PyNvJpeg 将 JPEG 编解码移到 GPU

pip install pynvjpeg

实施步骤

  1. 创建 gpu_jpeg.py 模块
  2. 修改 app_main.py 替换 turbo_decode/turbo_encode

问题 2TTS 语音不播放

状态 未解决

现象[TTS->WS] Buffering TTS audio, will send when reconnected

原因:音频 WebSocket 断开

问题 3画面卡顿/滞后

状态⚠️ 待问题 1 解决后验证


明日开发计划

  1. 安装 PyNvJpegpip 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)