# 性能优化:700Token并发100优化方案 v3.11.9 ## 📋 文档时间 2025-10-08 ## 🎯 场景说明 **实际需求:** - 总token数:**700+个** - 并发执行:**100个同时运行** - 总批次:**7批**(700 ÷ 100 = 7) - 关键目标:**降低CPU和内存开销** ## 📊 当前问题分析 ### 性能瓶颈 #### 1️⃣ 内存开销(最严重) ```javascript // 100个并发token的内存占用估算: 100个WebSocket连接: ~500-1000MB 100个token状态对象: ~50-100MB 100个Vue响应式代理: ~100-200MB 100个UI卡片DOM: ~200-300MB 执行进度数据: ~50-100MB 日志数据: ~100-200MB ------------------------------------------ 预估总内存: 1000-1900MB(1-2GB)⚠️ // 加上浏览器基础占用(约500MB) 总计: 1.5-2.5GB ``` **问题:** 浏览器可能崩溃或极度卡顿 #### 2️⃣ CPU开销 ```javascript // CPU占用来源: 1. 100个WebSocket消息处理 ← 主要 2. 100个Vue响应式更新 ← 主要 3. 100个UI卡片渲染 ← 主要 4. 日志输出(console.log) ← 次要 5. 任务进度计算 ← 次要 6. CSS动画 ← 次要 预估CPU占用:40-60% (多核情况下)⚠️ ``` #### 3️⃣ UI渲染压力 ```javascript // 100个token卡片同时更新: 每秒更新次数:100个 × 2次/秒 = 200次/秒 触发重排/重绘:频繁 滚动性能:卡顿 动画效果:掉帧 结果:界面卡顿严重 ⚠️ ``` --- ## ✅ 优化方案(七大维度) ### 🎯 方案1:虚拟滚动(最重要!) #### 问题 ``` 100个token卡片全部渲染在DOM中 → 大量DOM节点 → 内存和渲染压力巨大 ``` #### 解决方案 ```javascript // 实现虚拟滚动,只渲染可见区域 屏幕可见: 约15-20个卡片 预加载: 上下各5个 实际渲染: 约25-30个卡片 内存节省: 70%(100个 → 30个) 渲染性能提升: 3-5倍 ``` #### 实现建议 ```javascript // 使用 vue-virtual-scroller 或 vue-virtual-scroll-list // 或自己实现简单版本 // 核心思路: 1. 计算可见区域(viewport) 2. 只渲染可见+预加载的卡片 3. 监听滚动,动态更新渲染列表 4. 使用 transform 而非 top/margin 定位 ``` **预期效果:** - 内存:1.5GB → **800MB** ⬇️ 减少47% - CPU:50% → **25%** ⬇️ 减少50% - 渲染:卡顿 → **流畅** ✅ --- ### 🔇 方案2:禁用/优化日志输出 #### 问题 ```javascript // 100个token × 每秒10条日志 = 1000条/秒 console.log() 非常消耗性能 每条日志都会触发浏览器渲染 ``` #### 解决方案 ```javascript // 方案A:生产模式禁用日志(推荐) const DEBUG_MODE = false // 批量任务时设为false if (DEBUG_MODE) { console.log(...) } // 方案B:限制日志级别 只保留 error 和 warn 禁用 info 和 debug // 方案C:批量输出日志 每100条日志合并输出一次 而不是每条都立即输出 ``` **预期效果:** - CPU:-10-15% - 渲染流畅度:明显提升 --- ### ⚡ 方案3:UI更新节流 #### 问题 ```javascript // 100个token每500ms更新一次进度 // 每秒触发200次Vue响应式更新 taskProgress.value[tokenId].progress = 50 // 触发更新 ``` #### 解决方案 ```javascript // 使用节流(throttle)限制更新频率 // 当前:每个任务完成就更新 // 优化:每1-2秒批量更新一次 const updateBatch = new Map() let updateTimer = null function throttledUpdate(tokenId, updates) { updateBatch.set(tokenId, { ...updateBatch.get(tokenId), ...updates }) if (!updateTimer) { updateTimer = setTimeout(() => { // 批量应用所有更新 updateBatch.forEach((updates, id) => { Object.assign(taskProgress.value[id], updates) }) updateBatch.clear() updateTimer = null }, 1000) // 每秒更新一次 } } ``` **预期效果:** - Vue响应式更新:200次/秒 → **20次/秒** ⬇️ - CPU:-5-10% --- ### 🎨 方案4:禁用动画和过渡 #### 问题 ```javascript // CSS动画和过渡效果消耗GPU/CPU .card { transition: all 0.3s; animation: pulse 2s infinite; } ``` #### 解决方案 ```javascript // 在批量任务执行时禁用所有动画 // 方案A:添加CSS类 .batch-executing { * { animation: none !important; transition: none !important; } } // 方案B:JavaScript控制 document.body.classList.add('disable-animations') ``` **预期效果:** - GPU占用:-20-30% - 页面流畅度:提升 --- ### 💾 方案5:优化内存管理 #### 5.1 限制历史记录 ```javascript // 问题:保留所有执行历史 executionHistory.value.unshift(historyItem) // 优化:只保留最近的 if (executionHistory.value.length > 5) { // 改为5 executionHistory.value = executionHistory.value.slice(0, 5) } ``` #### 5.2 清理已完成的token数据 ```javascript // 问题:已完成的token仍保留完整数据 // 优化:只保留摘要信息 function compactCompletedToken(tokenId) { const progress = taskProgress.value[tokenId] if (progress.status === 'completed' || progress.status === 'failed') { // 只保留关键信息,清理详细数据 progress.result = null // 清理任务结果详情 progress.error = progress.error ? '错误已记录' : null } } ``` #### 5.3 WebSocket连接及时断开 ```javascript // 确保任务完成后立即断开连接 // 当前已实现,但要确保没有泄漏 finally { if (tokenStore.wsConnections[tokenId]) { tokenStore.closeWebSocketConnection(tokenId) } } ``` **预期效果:** - 内存占用:-200-400MB --- ### 🔧 方案6:优化WebSocket消息处理 #### 问题 ```javascript // 每条消息都触发复杂的响应式更新 socket.onmessage = (event) => { const data = parseMessage(event.data) // 触发多层响应式更新 store.messages.push(data) // 触发更新 store.unreadCount++ // 触发更新 updateUI() // 触发更新 } ``` #### 解决方案 ```javascript // 使用 nextTick 批量处理消息 const messageQueue = [] socket.onmessage = (event) => { messageQueue.push(event.data) // 使用 requestIdleCallback 在空闲时处理 requestIdleCallback(() => { const batch = messageQueue.splice(0, 100) processBatch(batch) }) } ``` **预期效果:** - 消息处理效率:提升30-50% - CPU尖刺:减少 --- ### ⏱️ 方案7:进一步缩短延迟时间 #### 当前配置 ```javascript 连接稳定等待: 2000ms 任务间隔: 500ms 连接间隔: 500ms ``` #### 优化配置(100并发专用) ```javascript 连接稳定等待: 300ms ⬇️(并发高时可以更短) 任务间隔: 200ms ⬇️ 连接间隔: 300ms ⬇️ 子任务延迟: 50-100ms ⬇️ ``` **原理:** - 100个并发时,等待时间可以重叠 - 不需要每个都等足2秒 - 通过并发实现"虚拟等待" **预期效果:** - 每个token节省:3-5秒 - 总时间节省:100个 × 4秒 = 400秒 --- ## 🔧 具体代码实施 ### 优先级1:立即实施(核心优化) #### ✅ 1. 禁用日志输出 在 `src/stores/batchTaskStore.js` 顶部添加: ```javascript // 批量任务性能优化:禁用日志 const ENABLE_BATCH_LOGS = false // 改为false // 包装所有console.log const batchLog = ENABLE_BATCH_LOGS ? console.log.bind(console) : () => {} // 替换所有 console.log 为 batchLog // 搜索:console.log // 替换:batchLog ``` #### ✅ 2. 缩短延迟时间 ```javascript // 第348行:连接稳定等待 await new Promise(resolve => setTimeout(resolve, 2000)) // 改为 await new Promise(resolve => setTimeout(resolve, 300)) // 第401行:任务间隔 await new Promise(resolve => setTimeout(resolve, 500)) // 改为 await new Promise(resolve => setTimeout(resolve, 200)) // 第259行:连接间隔 const delayMs = connectionIndex * 500 // 改为 const delayMs = connectionIndex * 300 ``` #### ✅ 3. 限制历史记录 ```javascript // 第1689行 if (executionHistory.value.length > 10) { executionHistory.value = executionHistory.value.slice(0, 10) } // 改为 if (executionHistory.value.length > 3) { executionHistory.value = executionHistory.value.slice(0, 3) } ``` #### ✅ 4. UI更新节流 在 `src/stores/batchTaskStore.js` 中添加: ```javascript // 更新进度节流 let updateThrottleTimer = null const pendingUpdates = new Map() const updateTaskProgressThrottled = (tokenId, updates) => { pendingUpdates.set(tokenId, { ...pendingUpdates.get(tokenId), ...updates }) if (!updateThrottleTimer) { updateThrottleTimer = setTimeout(() => { pendingUpdates.forEach((updates, id) => { if (taskProgress.value[id]) { Object.assign(taskProgress.value[id], updates) } }) pendingUpdates.clear() updateThrottleTimer = null }, 500) // 每500ms更新一次 } } // 在非关键更新处使用 updateTaskProgressThrottled // 关键更新(开始、结束、失败)仍使用 updateTaskProgress ``` --- ### 优先级2:重要优化(需要更多工作) #### ⭐ 虚拟滚动实现 这需要修改 `TaskProgressCard` 组件的渲染逻辑。 **简单方案:** ```vue ``` **预期效果:** - 内存:-800MB - CPU:-25% - 渲染:流畅 --- ## 📊 优化效果预估 ### 内存占用对比 | 项目 | 优化前 | 优化后 | 节省 | |------|--------|--------|------| | **DOM渲染** | 1000MB | 300MB | **-700MB** ⬇️ | | **日志数据** | 200MB | 20MB | **-180MB** ⬇️ | | **历史记录** | 100MB | 30MB | **-70MB** ⬇️ | | **其他** | 500MB | 450MB | -50MB | | **总计** | **1800MB** | **800MB** | **-1000MB (55%)** ⬇️ | ### CPU占用对比 | 项目 | 优化前 | 优化后 | 节省 | |------|--------|--------|------| | **UI渲染** | 20% | 5% | **-15%** ⬇️ | | **日志输出** | 10% | 1% | **-9%** ⬇️ | | **Vue更新** | 15% | 5% | **-10%** ⬇️ | | **WS消息** | 10% | 8% | -2% | | **任务逻辑** | 5% | 5% | 0% | | **总计** | **60%** | **24%** | **-36% (60%)** ⬇️ | ### 执行时间对比(700个token) | 方案 | 批次 | 单批时间 | 总时间 | |------|------|---------|--------| | **优化前** | 7批 | 3-4分钟 | **21-28分钟** | | **优化后** | 7批 | 1.5-2分钟 | **10.5-14分钟** ⬇️ | | **节省** | - | 1.5-2分钟 | **10-14分钟 (50%)** ⬇️ | --- ## ⚠️ 实施建议 ### 分阶段实施 #### 阶段1:立即可做(30分钟) ``` 1. ✅ 禁用日志输出 2. ✅ 缩短延迟时间 3. ✅ 限制历史记录 4. ✅ 测试50个token 预期效果:内存-300MB,CPU-15% ``` #### 阶段2:重要优化(2小时) ``` 1. ⭐ 实现虚拟滚动 2. ✅ UI更新节流 3. ✅ 禁用动画 4. ✅ 测试100个token 预期效果:内存-800MB,CPU-35% ``` #### 阶段3:全面测试(1天) ``` 1. 测试100并发 2. 测试700全量(7批) 3. 监控性能指标 4. 调优参数 ``` --- ### 测试检查清单 **启动前检查:** - [ ] 关闭其他浏览器标签页 - [ ] 关闭不必要的应用程序 - [ ] 确保内存 >4GB 可用 - [ ] 确保网络稳定 **运行中监控:** - [ ] 任务管理器监控内存(目标<2GB) - [ ] 任务管理器监控CPU(目标<40%) - [ ] 浏览器控制台无错误 - [ ] 页面可以正常滚动 **完成后检查:** - [ ] 成功率 >85% - [ ] 浏览器未崩溃 - [ ] 内存正常释放 - [ ] 记录实际数据 --- ## 💡 额外建议 ### 1. 分批策略优化 **不建议:** 一次100个 × 7批 **建议:** ``` 方案A:50个 × 14批(更稳定) 方案B:70个 × 10批(平衡) 方案C:100个 × 7批(激进,需全面优化) ``` ### 2. 时间分散 **建议:** ``` - 不要一口气跑完700个 - 分成早中晚3次,每次跑230个 - 避免长时间高负载 ``` ### 3. 备用方案 如果浏览器仍然吃不消: **方案A:使用多个浏览器实例** ``` 浏览器1:运行350个token(并发50) 浏览器2:运行350个token(并发50) ``` **方案B:使用Headless模式** ``` 使用Puppeteer/Playwright 无UI运行,内存占用更小 ``` --- ## 📝 需要我立即实施的代码修改 我可以马上帮您修改: ### ✅ 核心优化(推荐立即实施) 1. 禁用日志输出 2. 缩短延迟时间(300ms/200ms/300ms) 3. 限制历史记录(10条→3条) 4. UI更新节流(每500ms) **预期效果:** - 内存:1800MB → **1200MB** ⬇️ - CPU:60% → **35%** ⬇️ - 时间:21分钟 → **14分钟** ⬇️ ### ⭐ 重要优化(需要更多时间) 5. 虚拟滚动(需要1-2小时) 6. 禁用动画 7. WebSocket消息批处理 **预期效果:** - 内存:1200MB → **800MB** ⬇️ - CPU:35% → **24%** ⬇️ - 时间:14分钟 → **10.5分钟** ⬇️ --- ## 🚀 请确认 **您希望我现在:** 1. ✅ 立即实施核心优化(4项修改)? 2. ⭐ 同时实施虚拟滚动(需要更多时间)? 3. 📋 还是先提供完整修改清单,您自行决定? **或者您想先测试:** - 调整并发数到50或70,看看现状能否承受? 请告诉我您的选择! 🎯