# 异步处理机制
## 🎯 学习目标
通过本章学习,您将能够:
- 理解AI集成中异步处理的重要性和优势
- 掌握异步任务队列和并发控制技术
- 学会设计高性能的AI服务架构
- 在Chat-Room项目中实现流畅的AI交互体验
## ⚡ 异步处理架构
### 异步AI处理系统概览
```mermaid
graph TB
subgraph "异步AI处理系统"
A[用户请求
User Request] --> B[请求验证
Request Validation]
B --> C[任务队列
Task Queue]
C --> D[任务调度器
Task Scheduler]
D --> E[AI工作池
AI Worker Pool]
E --> F[API调用
API Call]
F --> G[响应处理
Response Processing]
G --> H[结果缓存
Result Cache]
H --> I[消息推送
Message Push]
J[负载均衡
Load Balancer] --> E
K[监控系统
Monitoring] --> D
L[错误处理
Error Handler] --> G
M[重试机制
Retry Logic] --> F
end
subgraph "异步组件"
N[任务队列
Redis/RabbitMQ]
O[WebSocket
Real-time Push]
P[缓存层
Cache Layer]
Q[数据库
Database]
end
C --> N
I --> O
H --> P
G --> Q
style A fill:#e8f5e8
style I fill:#f8d7da
```
### 异步处理流程
```mermaid
sequenceDiagram
participant U as 用户
participant C as 客户端
participant S as 服务器
participant Q as 任务队列
participant W as AI工作器
participant AI as AI API
participant WS as WebSocket
Note over U,WS: 异步AI处理流程
U->>C: 发送AI请求
C->>S: 提交请求
S->>S: 生成任务ID
S->>Q: 加入任务队列
S->>C: 返回任务ID
C->>U: 显示"处理中..."
Q->>W: 分配任务
W->>AI: 调用AI API
alt API调用成功
AI->>W: 返回AI响应
W->>S: 处理完成
S->>WS: 推送结果
WS->>C: 实时更新
C->>U: 显示AI回复
else API调用失败
AI->>W: 返回错误
W->>W: 重试逻辑
alt 重试成功
W->>S: 处理完成
else 重试失败
W->>S: 处理失败
S->>WS: 推送错误
WS->>C: 显示错误信息
end
end
```
## 🔄 异步处理实现
### 异步AI任务管理器
```python
# server/ai/async_processor.py - 异步AI处理器
import asyncio
import json
import time
import uuid
from typing import Dict, List, Optional, Any, Callable, Coroutine
from dataclasses import dataclass, asdict
from enum import Enum
import aioredis
import logging
from concurrent.futures import ThreadPoolExecutor
class TaskStatus(Enum):
"""任务状态"""
PENDING = "pending"
PROCESSING = "processing"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
RETRYING = "retrying"
class TaskPriority(Enum):
"""任务优先级"""
LOW = 1
NORMAL = 2
HIGH = 3
URGENT = 4
@dataclass
class AITask:
"""AI任务"""
task_id: str
user_id: int
request_type: str
request_data: Dict[str, Any]
priority: TaskPriority = TaskPriority.NORMAL
status: TaskStatus = TaskStatus.PENDING
created_at: float = None
started_at: Optional[float] = None
completed_at: Optional[float] = None
result: Optional[Dict[str, Any]] = None
error_message: Optional[str] = None
retry_count: int = 0
max_retries: int = 3
timeout: float = 30.0
def __post_init__(self):
if self.created_at is None:
self.created_at = time.time()
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
data = asdict(self)
data['priority'] = self.priority.value
data['status'] = self.status.value
return data
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'AITask':
"""从字典创建"""
data['priority'] = TaskPriority(data['priority'])
data['status'] = TaskStatus(data['status'])
return cls(**data)
class AsyncAIProcessor:
"""
异步AI处理器
功能:
1. 异步任务队列管理
2. 并发AI API调用
3. 实时结果推送
4. 错误处理和重试
5. 性能监控和优化
"""
def __init__(self, redis_url: str = "redis://localhost:6379",
max_workers: int = 10, max_concurrent_tasks: int = 50):
self.redis_url = redis_url
self.max_workers = max_workers
self.max_concurrent_tasks = max_concurrent_tasks
# Redis连接
self.redis: Optional[aioredis.Redis] = None
# 任务管理
self.active_tasks: Dict[str, AITask] = {}
self.task_semaphore = asyncio.Semaphore(max_concurrent_tasks)
# 工作器管理
self.workers: List[asyncio.Task] = []
self.worker_pool = ThreadPoolExecutor(max_workers=max_workers)
# 事件回调
self.task_callbacks: Dict[str, List[Callable]] = {
'task_started': [],
'task_completed': [],
'task_failed': [],
'task_progress': []
}
# 统计信息
self.stats = {
'total_tasks': 0,
'completed_tasks': 0,
'failed_tasks': 0,
'average_processing_time': 0.0,
'current_queue_size': 0
}
self.logger = logging.getLogger('AsyncAIProcessor')
self.running = False
async def start(self):
"""启动异步处理器"""
if self.running:
return
# 连接Redis
self.redis = await aioredis.from_url(self.redis_url)
# 启动工作器
for i in range(self.max_workers):
worker = asyncio.create_task(self._worker_loop(f"worker-{i}"))
self.workers.append(worker)
# 启动监控任务
asyncio.create_task(self._monitor_loop())
self.running = True
self.logger.info(f"异步AI处理器已启动,工作器数量: {self.max_workers}")
async def stop(self):
"""停止异步处理器"""
if not self.running:
return
self.running = False
# 停止工作器
for worker in self.workers:
worker.cancel()
# 等待工作器结束
await asyncio.gather(*self.workers, return_exceptions=True)
# 关闭Redis连接
if self.redis:
await self.redis.close()
# 关闭线程池
self.worker_pool.shutdown(wait=True)
self.logger.info("异步AI处理器已停止")
async def submit_task(self, user_id: int, request_type: str,
request_data: Dict[str, Any],
priority: TaskPriority = TaskPriority.NORMAL,
timeout: float = 30.0) -> str:
"""
提交AI任务
Args:
user_id: 用户ID
request_type: 请求类型
request_data: 请求数据
priority: 任务优先级
timeout: 超时时间
Returns:
任务ID
"""
# 生成任务ID
task_id = str(uuid.uuid4())
# 创建任务
task = AITask(
task_id=task_id,
user_id=user_id,
request_type=request_type,
request_data=request_data,
priority=priority,
timeout=timeout
)
# 添加到Redis队列
queue_name = f"ai_tasks:{priority.name.lower()}"
await self.redis.lpush(queue_name, json.dumps(task.to_dict()))
# 更新统计
self.stats['total_tasks'] += 1
self.stats['current_queue_size'] = await self._get_queue_size()
self.logger.info(f"任务已提交: {task_id}, 类型: {request_type}, 用户: {user_id}")
return task_id
async def get_task_status(self, task_id: str) -> Optional[Dict[str, Any]]:
"""获取任务状态"""
# 先检查活跃任务
if task_id in self.active_tasks:
return self.active_tasks[task_id].to_dict()
# 从Redis获取
task_data = await self.redis.get(f"task_result:{task_id}")
if task_data:
return json.loads(task_data)
return None
async def cancel_task(self, task_id: str) -> bool:
"""取消任务"""
# 检查活跃任务
if task_id in self.active_tasks:
task = self.active_tasks[task_id]
task.status = TaskStatus.CANCELLED
return True
# 从队列中移除(这里简化处理)
return False
def add_callback(self, event_type: str, callback: Callable):
"""添加事件回调"""
if event_type in self.task_callbacks:
self.task_callbacks[event_type].append(callback)
async def _worker_loop(self, worker_name: str):
"""工作器主循环"""
self.logger.info(f"工作器 {worker_name} 已启动")
while self.running:
try:
# 获取任务(按优先级)
task = await self._get_next_task()
if not task:
await asyncio.sleep(0.1)
continue
# 处理任务
async with self.task_semaphore:
await self._process_task(task, worker_name)
except asyncio.CancelledError:
break
except Exception as e:
self.logger.error(f"工作器 {worker_name} 异常: {e}")
await asyncio.sleep(1)
self.logger.info(f"工作器 {worker_name} 已停止")
async def _get_next_task(self) -> Optional[AITask]:
"""获取下一个任务"""
# 按优先级顺序检查队列
for priority in [TaskPriority.URGENT, TaskPriority.HIGH,
TaskPriority.NORMAL, TaskPriority.LOW]:
queue_name = f"ai_tasks:{priority.name.lower()}"
task_data = await self.redis.brpop(queue_name, timeout=1)
if task_data:
task_dict = json.loads(task_data[1])
return AITask.from_dict(task_dict)
return None
async def _process_task(self, task: AITask, worker_name: str):
"""处理单个任务"""
task.status = TaskStatus.PROCESSING
task.started_at = time.time()
self.active_tasks[task.task_id] = task
# 触发开始事件
await self._trigger_event('task_started', task)
try:
# 根据请求类型处理任务
if task.request_type == "chat_completion":
result = await self._process_chat_completion(task)
elif task.request_type == "content_summary":
result = await self._process_content_summary(task)
elif task.request_type == "translation":
result = await self._process_translation(task)
else:
raise ValueError(f"未知的请求类型: {task.request_type}")
# 任务完成
task.status = TaskStatus.COMPLETED
task.completed_at = time.time()
task.result = result
# 保存结果到Redis
await self._save_task_result(task)
# 触发完成事件
await self._trigger_event('task_completed', task)
# 更新统计
self.stats['completed_tasks'] += 1
processing_time = task.completed_at - task.started_at
self._update_average_processing_time(processing_time)
self.logger.info(f"任务完成: {task.task_id}, 耗时: {processing_time:.2f}s")
except Exception as e:
# 任务失败
task.status = TaskStatus.FAILED
task.error_message = str(e)
task.completed_at = time.time()
# 检查是否需要重试
if task.retry_count < task.max_retries:
task.retry_count += 1
task.status = TaskStatus.RETRYING
# 重新加入队列
queue_name = f"ai_tasks:{task.priority.name.lower()}"
await self.redis.lpush(queue_name, json.dumps(task.to_dict()))
self.logger.warning(f"任务重试: {task.task_id}, 重试次数: {task.retry_count}")
else:
# 触发失败事件
await self._trigger_event('task_failed', task)
# 更新统计
self.stats['failed_tasks'] += 1
self.logger.error(f"任务失败: {task.task_id}, 错误: {e}")
finally:
# 从活跃任务中移除
if task.task_id in self.active_tasks:
del self.active_tasks[task.task_id]
async def _process_chat_completion(self, task: AITask) -> Dict[str, Any]:
"""处理聊天完成任务"""
# 这里应该调用实际的AI API
# 为了演示,我们模拟一个异步API调用
await asyncio.sleep(1) # 模拟API调用延迟
return {
"response": f"这是对用户{task.user_id}消息的AI回复",
"tokens_used": 150,
"model": "glm-4-flash"
}
async def _process_content_summary(self, task: AITask) -> Dict[str, Any]:
"""处理内容总结任务"""
await asyncio.sleep(0.5) # 模拟处理时间
return {
"summary": "这是内容总结",
"key_points": ["要点1", "要点2", "要点3"],
"tokens_used": 80
}
async def _process_translation(self, task: AITask) -> Dict[str, Any]:
"""处理翻译任务"""
await asyncio.sleep(0.3) # 模拟处理时间
return {
"translated_text": "这是翻译结果",
"source_language": "zh",
"target_language": "en",
"confidence": 0.95
}
async def _save_task_result(self, task: AITask):
"""保存任务结果"""
result_key = f"task_result:{task.task_id}"
result_data = json.dumps(task.to_dict())
# 设置过期时间(1小时)
await self.redis.setex(result_key, 3600, result_data)
async def _trigger_event(self, event_type: str, task: AITask):
"""触发事件回调"""
for callback in self.task_callbacks.get(event_type, []):
try:
if asyncio.iscoroutinefunction(callback):
await callback(task)
else:
callback(task)
except Exception as e:
self.logger.error(f"事件回调异常: {e}")
async def _get_queue_size(self) -> int:
"""获取队列大小"""
total_size = 0
for priority in TaskPriority:
queue_name = f"ai_tasks:{priority.name.lower()}"
size = await self.redis.llen(queue_name)
total_size += size
return total_size
def _update_average_processing_time(self, processing_time: float):
"""更新平均处理时间"""
completed = self.stats['completed_tasks']
if completed == 1:
self.stats['average_processing_time'] = processing_time
else:
current_avg = self.stats['average_processing_time']
self.stats['average_processing_time'] = (current_avg * (completed - 1) + processing_time) / completed
async def _monitor_loop(self):
"""监控循环"""
while self.running:
try:
# 更新队列大小统计
self.stats['current_queue_size'] = await self._get_queue_size()
# 记录统计信息
if self.stats['total_tasks'] % 100 == 0 and self.stats['total_tasks'] > 0:
self.logger.info(f"处理统计: {self.stats}")
await asyncio.sleep(10) # 每10秒监控一次
except Exception as e:
self.logger.error(f"监控循环异常: {e}")
await asyncio.sleep(5)
def get_stats(self) -> Dict[str, Any]:
"""获取统计信息"""
stats = self.stats.copy()
stats['active_tasks_count'] = len(self.active_tasks)
stats['worker_count'] = len(self.workers)
if stats['total_tasks'] > 0:
stats['success_rate'] = stats['completed_tasks'] / stats['total_tasks']
stats['failure_rate'] = stats['failed_tasks'] / stats['total_tasks']
else:
stats['success_rate'] = 0.0
stats['failure_rate'] = 0.0
return stats
# 使用示例
async def demo_async_processor():
"""异步处理器演示"""
processor = AsyncAIProcessor(max_workers=3)
# 添加事件回调
async def on_task_completed(task: AITask):
print(f"任务完成: {task.task_id}, 结果: {task.result}")
def on_task_failed(task: AITask):
print(f"任务失败: {task.task_id}, 错误: {task.error_message}")
processor.add_callback('task_completed', on_task_completed)
processor.add_callback('task_failed', on_task_failed)
print("=== 异步AI处理器演示 ===")
try:
# 启动处理器
await processor.start()
# 提交任务
tasks = []
for i in range(5):
task_id = await processor.submit_task(
user_id=i + 1,
request_type="chat_completion",
request_data={"message": f"测试消息 {i + 1}"},
priority=TaskPriority.NORMAL
)
tasks.append(task_id)
print(f"提交任务: {task_id}")
# 等待任务完成
await asyncio.sleep(5)
# 查看任务状态
for task_id in tasks:
status = await processor.get_task_status(task_id)
if status:
print(f"任务 {task_id}: {status['status']}")
# 查看统计信息
stats = processor.get_stats()
print(f"处理统计: {stats}")
finally:
# 停止处理器
await processor.stop()
if __name__ == "__main__":
asyncio.run(demo_async_processor())
```
## 🎯 实践练习
### 练习1:流式响应处理
```python
class StreamingResponseHandler:
"""
流式响应处理练习
要求:
1. 实现AI流式响应的实时推送
2. 支持部分结果的增量更新
3. 处理流式响应的错误和中断
4. 优化用户体验和响应速度
"""
async def handle_streaming_response(self, task_id: str, response_stream):
"""处理流式响应"""
# TODO: 实现流式响应处理
pass
```
### 练习2:智能任务调度
```python
class IntelligentTaskScheduler:
"""
智能任务调度练习
要求:
1. 基于用户优先级和历史行为调度任务
2. 实现动态负载均衡
3. 支持任务依赖和批处理
4. 优化资源利用率和响应时间
"""
def calculate_task_priority(self, task: AITask, user_context: Dict) -> float:
"""计算任务优先级"""
# TODO: 实现智能优先级计算
pass
```
## ✅ 学习检查
完成本章学习后,请确认您能够:
- [ ] 理解异步处理在AI集成中的重要性
- [ ] 设计高效的异步任务队列系统
- [ ] 实现并发AI API调用和结果处理
- [ ] 管理任务状态和错误处理
- [ ] 优化异步处理性能和用户体验
- [ ] 完成实践练习
## 📚 下一步
异步处理机制掌握后,请继续学习:
- [第8章:用户界面设计](../12-user-interface/tui-concepts.md)
---
**恭喜!您已经完成了AI集成功能的学习!** ⚡