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

241 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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%+**
- 导航场景8fpsYOLO 约 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 密集型任务。
---
## 遗留问题与解决方案
### 问题 1CPU 单线程瓶颈
**状态**:❌ 未解决
**解决方案**:使用 **PyNvJpeg** 将 JPEG 编解码移到 GPU
```bash
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. **安装 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) |