Files
xyzw_web_helper/MD说明文件夹/性能优化-700Token并发100优化方案v3.11.9.md
2025-10-17 20:56:50 +08:00

14 KiB
Raw Blame History

性能优化700Token并发100优化方案 v3.11.9

📋 文档时间

2025-10-08

🎯 场景说明

实际需求:

  • 总token数700+个
  • 并发执行:100个同时运行
  • 总批次:7批700 ÷ 100 = 7
  • 关键目标:降低CPU和内存开销

📊 当前问题分析

性能瓶颈

1 内存开销(最严重)

// 100个并发token的内存占用估算
100个WebSocket连接        ~500-1000MB
100个token状态对象         ~50-100MB
100个Vue响应式代理         ~100-200MB
100个UI卡片DOM            ~200-300MB
执行进度数据               ~50-100MB
日志数据                   ~100-200MB
------------------------------------------
预估总内存                 1000-1900MB1-2GB)⚠️

// 加上浏览器基础占用约500MB
总计                       1.5-2.5GB

问题: 浏览器可能崩溃或极度卡顿

2 CPU开销

// CPU占用来源
1. 100个WebSocket消息处理     主要
2. 100个Vue响应式更新          主要
3. 100个UI卡片渲染             主要
4. 日志输出console.log     次要
5. 任务进度计算                次要
6. CSS动画                     次要

预估CPU占用40-60% 多核情况下)⚠️

3 UI渲染压力

// 100个token卡片同时更新
每秒更新次数100 × 2/ = 200/
触发重排/重绘频繁
滚动性能卡顿
动画效果掉帧

结果界面卡顿严重 ⚠️

优化方案(七大维度)

🎯 方案1虚拟滚动最重要

问题

100个token卡片全部渲染在DOM中
→ 大量DOM节点
→ 内存和渲染压力巨大

解决方案

// 实现虚拟滚动,只渲染可见区域
屏幕可见       约15-20个卡片
预加载         上下各5个
实际渲染       约25-30个卡片

内存节省       70%100  30
渲染性能提升   3-5

实现建议

// 使用 vue-virtual-scroller 或 vue-virtual-scroll-list
// 或自己实现简单版本

// 核心思路:
1. 计算可见区域viewport
2. 只渲染可见+预加载的卡片
3. 监听滚动动态更新渲染列表
4. 使用 transform 而非 top/margin 定位

预期效果:

  • 内存1.5GB → 800MB ⬇️ 减少47%
  • CPU50% → 25% ⬇️ 减少50%
  • 渲染:卡顿 → 流畅

🔇 方案2禁用/优化日志输出

问题

// 100个token × 每秒10条日志 = 1000条/秒
console.log() 非常消耗性能
每条日志都会触发浏览器渲染

解决方案

// 方案A生产模式禁用日志推荐
const DEBUG_MODE = false  // 批量任务时设为false

if (DEBUG_MODE) {
  console.log(...)
}

// 方案B限制日志级别
只保留 error  warn
禁用 info  debug

// 方案C批量输出日志
每100条日志合并输出一次
而不是每条都立即输出

预期效果:

  • CPU-10-15%
  • 渲染流畅度:明显提升

方案3UI更新节流

问题

// 100个token每500ms更新一次进度
// 每秒触发200次Vue响应式更新
taskProgress.value[tokenId].progress = 50  // 触发更新

解决方案

// 使用节流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禁用动画和过渡

问题

// CSS动画和过渡效果消耗GPU/CPU
.card {
  transition: all 0.3s;
  animation: pulse 2s infinite;
}

解决方案

// 在批量任务执行时禁用所有动画

// 方案A添加CSS类
.batch-executing {
  * {
    animation: none !important;
    transition: none !important;
  }
}

// 方案BJavaScript控制
document.body.classList.add('disable-animations')

预期效果:

  • GPU占用-20-30%
  • 页面流畅度:提升

💾 方案5优化内存管理

5.1 限制历史记录

// 问题:保留所有执行历史
executionHistory.value.unshift(historyItem)

// 优化:只保留最近的
if (executionHistory.value.length > 5) {  // 改为5
  executionHistory.value = executionHistory.value.slice(0, 5)
}

5.2 清理已完成的token数据

// 问题已完成的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连接及时断开

// 确保任务完成后立即断开连接
// 当前已实现,但要确保没有泄漏

finally {
  if (tokenStore.wsConnections[tokenId]) {
    tokenStore.closeWebSocketConnection(tokenId)
  }
}

预期效果:

  • 内存占用:-200-400MB

🔧 方案6优化WebSocket消息处理

问题

// 每条消息都触发复杂的响应式更新
socket.onmessage = (event) => {
  const data = parseMessage(event.data)
  // 触发多层响应式更新
  store.messages.push(data)  // 触发更新
  store.unreadCount++        // 触发更新
  updateUI()                 // 触发更新
}

解决方案

// 使用 nextTick 批量处理消息
const messageQueue = []

socket.onmessage = (event) => {
  messageQueue.push(event.data)
  
  // 使用 requestIdleCallback 在空闲时处理
  requestIdleCallback(() => {
    const batch = messageQueue.splice(0, 100)
    processBatch(batch)
  })
}

预期效果:

  • 消息处理效率提升30-50%
  • CPU尖刺减少

⏱️ 方案7进一步缩短延迟时间

当前配置

连接稳定等待: 2000ms
任务间隔: 500ms
连接间隔: 500ms

优化配置100并发专用

连接稳定等待: 300ms   ⬇️(并发高时可以更短
任务间隔: 200ms        ⬇️
连接间隔: 300ms        ⬇️
子任务延迟: 50-100ms   ⬇️

原理:

  • 100个并发时等待时间可以重叠
  • 不需要每个都等足2秒
  • 通过并发实现"虚拟等待"

预期效果:

  • 每个token节省3-5秒
  • 总时间节省100个 × 4秒 = 400秒

🔧 具体代码实施

优先级1立即实施核心优化

1. 禁用日志输出

src/stores/batchTaskStore.js 顶部添加:

// 批量任务性能优化:禁用日志
const ENABLE_BATCH_LOGS = false  // 改为false

// 包装所有console.log
const batchLog = ENABLE_BATCH_LOGS ? console.log.bind(console) : () => {}

// 替换所有 console.log 为 batchLog
// 搜索console.log
// 替换batchLog

2. 缩短延迟时间

// 第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. 限制历史记录

// 第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 中添加:

// 更新进度节流
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 组件的渲染逻辑。

简单方案:

<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

预期效果:内存-300MBCPU-15%

阶段2重要优化2小时

1. ⭐ 实现虚拟滚动
2. ✅ UI更新节流
3. ✅ 禁用动画
4. ✅ 测试100个token

预期效果:内存-800MBCPU-35%

阶段3全面测试1天

1. 测试100并发
2. 测试700全量7批
3. 监控性能指标
4. 调优参数

测试检查清单

启动前检查:

  • 关闭其他浏览器标签页
  • 关闭不必要的应用程序
  • 确保内存 >4GB 可用
  • 确保网络稳定

运行中监控:

  • 任务管理器监控内存(目标<2GB
  • 任务管理器监控CPU目标<40%
  • 浏览器控制台无错误
  • 页面可以正常滚动

完成后检查:

  • 成功率 >85%
  • 浏览器未崩溃
  • 内存正常释放
  • 记录实际数据

💡 额外建议

1. 分批策略优化

不建议: 一次100个 × 7批 建议:

方案A50个 × 14批更稳定
方案B70个 × 10批平衡
方案C100个 × 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 ⬇️
  • CPU60% → 35% ⬇️
  • 时间21分钟 → 14分钟 ⬇️

重要优化(需要更多时间)

  1. 虚拟滚动需要1-2小时
  2. 禁用动画
  3. WebSocket消息批处理

预期效果:

  • 内存1200MB → 800MB ⬇️
  • CPU35% → 24% ⬇️
  • 时间14分钟 → 10.5分钟 ⬇️

🚀 请确认

您希望我现在:

  1. 立即实施核心优化4项修改
  2. 同时实施虚拟滚动(需要更多时间)?
  3. 📋 还是先提供完整修改清单,您自行决定?

或者您想先测试:

  • 调整并发数到50或70看看现状能否承受

请告诉我您的选择! 🎯