ASYNC_OPTIMIZATION.md 5.3 KB

异步并发优化说明

🎯 问题分析

原有实现的问题

  1. 使用同步 HTTP 请求 (requests.post):即使在 ThreadPoolExecutor 中,每个线程也是阻塞等待响应
  2. GIL 限制:Python 的全局解释器锁使得多线程在 I/O 密集型任务上性能提升有限
  3. 没有真正的并发:5 个请求实际上是顺序执行,时间累加

优化方案

  • ✅ 使用 asyncio + httpx 实现真正的异步并发
  • ✅ 所有 HTTP 请求真正并行发送和接收
  • ✅ 详细的性能日志,可以清楚看到并发效果

🚀 核心改进

1. 使用异步 HTTP 客户端

# ❌ 旧版本(同步阻塞)
response = requests.post(url, json=data)

# ✅ 新版本(异步非阻塞)
async with httpx.AsyncClient() as client:
    response = await client.post(url, json=data)

2. 并发执行所有任务

# 创建所有异步任务
coroutines = [
    self.extract_part_info(client, image_base64, prompt, task_name)
    for task_name, prompt in tasks.items()
]

# 真正并发执行(5 个请求同时发送)
results_list = await asyncio.gather(*coroutines)

3. 性能监控日志

  • 每个任务的开始时间
  • 每个任务的完成时间和耗时
  • 总体执行时间和并发加速比

📊 预期性能提升

场景分析

假设每个 OCR 请求耗时 10 秒:

实现方式 执行时间 说明
同步串行 ~50 秒 5 个请求 × 10 秒 = 50 秒
多线程 ~45-50 秒 受 GIL 限制,提升有限
异步并发 ~10-12 秒 真正并发,接近单个请求时间

理论加速比:约 4-5 倍 🚀


🧪 如何测试

1. 确保后端 API 服务运行

# 启动 FastAPI 服务
python -m model.model_api

2. 运行性能测试

python test_async_performance.py

3. 观察输出日志

你会看到类似这样的输出:

============================================================
[0.000s] 🎯 开始异步并发处理...
============================================================

[0.123s] 🚀 开始任务: name
[0.124s] 🚀 开始任务: tag
[0.125s] 🚀 开始任务: risk_notice
[0.126s] 🚀 开始任务: pre_notice
[0.127s] 🚀 开始任务: suppliers

[10.456s] ✅ 完成任务: name (耗时: 10.333s)
[10.789s] ✅ 完成任务: tag (耗时: 10.665s)
[11.012s] ✅ 完成任务: risk_notice (耗时: 10.887s)
[11.234s] ✅ 完成任务: pre_notice (耗时: 11.108s)
[11.567s] ✅ 完成任务: suppliers (耗时: 11.440s)

============================================================
⏱️  总推理时间: 11.567000 秒
📊 平均每个任务: 2.313400 秒
🚀 并发加速比: ~5.0x (理论值)
============================================================

关键观察点:

  • ✅ 所有任务几乎同时开始(0.123s ~ 0.127s)
  • ✅ 总时间接近单个任务的时间,而不是累加
  • ✅ 这就是真正的异步并发效果!

🔧 使用方式

方式 1:使用原有接口(推荐)

from PIL import Image
from agent.agent import OcrAgent

image = Image.open("test.jpg").convert("RGB")
agent = OcrAgent()
result = agent.agent_ocr(image)  # 自动使用异步实现

方式 2:直接使用异步接口

import asyncio
from PIL import Image
from agent.agent import OcrAgent

async def main():
    image = Image.open("test.jpg").convert("RGB")
    agent = OcrAgent()
    result = await agent.agent_ocr_async(image)
    return result

result = asyncio.run(main())

⚠️ 注意事项

1. 服务端并发限制

虽然客户端现在是真正并发,但服务端的处理能力取决于:

  • GPU 资源:大多数深度学习模型在单 GPU 上仍然是串行执行
  • 并发控制model_api.py 中设置了 max_concurrent=10

2. 如果仍然感觉慢

可能的原因:

  1. 服务端成为瓶颈:模型推理本身需要时间
  2. 网络传输:Base64 编码的图片数据较大
  3. 模型串行执行:即使并发请求,GPU 上可能仍然串行处理

3. 进一步优化方向

如果需要更快的速度:

  • 🔥 批量推理:将多个请求合并为一个批次
  • 🔥 模型量化:减少模型大小和推理时间
  • 🔥 多 GPU:使用多个 GPU 并行处理
  • 🔥 缓存:对相同图片和提示词缓存结果

📝 代码变更总结

文件修改

  • agent/agent.py - 改用 asyncio + httpx
  • ✅ 新增 test_async_performance.py - 性能测试脚本
  • ✅ 新增 requirements_async.txt - 异步依赖

依赖安装

pip install httpx>=0.25.0

✅ 测试清单

  • 确认 httpx 已安装 (pip install httpx)
  • 启动后端 API 服务
  • 运行 python test_async_performance.py
  • 观察日志中的时间戳(所有任务应同时开始)
  • 对比总执行时间(应显著减少)

🎉 总结

通过这次优化,我们实现了:

  1. 真正的异步并发:使用 asyncio + httpx 替代 ThreadPoolExecutor + requests
  2. 详细的性能日志:可以清楚看到每个任务的执行时间线
  3. 向后兼容:保留了原有的同步接口
  4. 预期加速比:理论上可达 4-5 倍(取决于服务端能力)

现在运行 test_async_performance.py,你应该能清楚地看到并发效果!🚀