617 lines
14 KiB
Markdown
617 lines
14 KiB
Markdown
|
|
# 性能优化: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
|
|||
|
|
<template>
|
|||
|
|
<div class="token-list-container" @scroll="handleScroll">
|
|||
|
|
<div class="token-list-spacer" :style="{ height: totalHeight + 'px' }">
|
|||
|
|
<div class="token-list-visible" :style="{ transform: `translateY(${offsetY}px)` }">
|
|||
|
|
<TaskProgressCard
|
|||
|
|
v-for="token in visibleTokens"
|
|||
|
|
:key="token.id"
|
|||
|
|
:token="token"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
const CARD_HEIGHT = 200 // 每个卡片高度
|
|||
|
|
const VISIBLE_COUNT = 20 // 可见数量
|
|||
|
|
const BUFFER_COUNT = 5 // 缓冲数量
|
|||
|
|
|
|||
|
|
const visibleTokens = computed(() => {
|
|||
|
|
const start = Math.max(0, scrollTop.value - BUFFER_COUNT)
|
|||
|
|
const end = Math.min(tokens.length, start + VISIBLE_COUNT + BUFFER_COUNT * 2)
|
|||
|
|
return tokens.slice(start, end)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const totalHeight = computed(() => tokens.length * CARD_HEIGHT)
|
|||
|
|
const offsetY = computed(() => scrollTop.value * CARD_HEIGHT)
|
|||
|
|
</script>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**预期效果:**
|
|||
|
|
- 内存:-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,看看现状能否承受?
|
|||
|
|
|
|||
|
|
请告诉我您的选择! 🎯
|
|||
|
|
|