performance-optimization-plan.md 4.3 KB

YZWater3 性能优化计划

创建时间:2026-09-01 01:12 计划执行时间:2026-09-01 03:14(定时触发逐个完成)


已知编译问题(已修复)

文件 行号 问题 状态
DeviceStateMachine.cs 122 OnTransitionException 在 Stateless 5.20.1 中不存在 ✅ 已修复:改用 FireSafe() 包裹异常

优化任务清单

🔴 高优先级(直接影响用户体验)

任务1: UI定时器无效重绘 - PumpStation2DControl

  • 文件: src/YZWater.Avalonia/Controls/PumpStation2DControl.cs:98
  • 问题: 33ms定时器(30FPS)每帧无条件调用 InvalidateVisual(),即使没有泵/风扇在运行
  • 修复: 仅在动画状态变化(泵转动、风扇转动)时才调用 InvalidateVisual()
  • 预期收益: 静止画面CPU占用降低80%+

任务2: UI定时器无效重绘 - PumpStation3DControl

  • 文件: src/YZWater.Avalonia/Controls/PumpStation3DControl.cs:89
  • 问题: 40ms定时器(25FPS)每帧无条件 InvalidateVisual()
  • 修复: 同上,仅在状态变化时重绘
  • 预期收益: 同任务1

任务3: 渲染循环中 SolidColorBrush 缓存

  • 文件: PumpStation2DControl.cs:274,279,297、PumpStation3DControl.cs:154,156,167
  • 问题: 每帧 new SolidColorBrush() 产生大量GC压力
  • 修复: 将常用颜色缓存为 static readonly 字段
  • 预期收益: 减少GC频率,消除画面卡顿

任务4: 渲染循环中 FormattedText 缓存

  • 文件: GaugeControl.cs:63-70、PumpStation2DControl.cs 多处 DrawLabel
  • 问题: 每帧创建 FormattedText 对象,文本测量开销大
  • 修复: 文本不变时复用 FormattedText 实例
  • 预期收益: 减少CPU开销

🟡 中优先级(内存泄漏 + 数据层)

任务5: 事件处理器泄漏 - MainViewModel

  • 文件: src/YZWater.Core/ViewModels/MainViewModel.cs:411-412
  • 问题: Dispose() 只释放 ViewA 和 Project ViewModel,ViewB~ViewF 未释放
  • 修复: 补全所有子 ViewModel 的 Dispose 调用
  • 预期收益: 防止内存持续增长

任务6: 事件处理器泄漏 - ViewAViewModel

  • 文件: src/YZWater.Core/ViewModels/ViewAViewModel.cs:171-175
  • 问题: 订阅静态单例事件但 Dispose 可能不被调用
  • 修复: 在 View 的 Unloaded 事件中确保 Dispose 被调用
  • 预期收益: 防止重复导航导致的内存泄漏

任务7: 数据库N+1查询

  • 文件: src/YZWater.Core/Services/DataLoggingService.cs:66-77
  • 问题: 全表加载 EquipmentStatus 再 GroupBy 取最新
  • 修复: 使用 SQL 子查询,只取每个设备最新记录
  • 预期收益: 启动速度提升,内存占用降低

任务8: 数据库索引缺失

  • 文件: src/YZWater.Core/Services/DatabaseService.cs:46-61
  • 问题: 表创建时未定义索引
  • 修复: 给 RecordTime、AlarmTime、LastUpdateTime、DeviceId 添加索引
  • 预期收益: 查询性能提升

任务9: PLC读取未批量化(ProjectProfile模式)

  • 文件: src/YZWater.Core/Services/PlcPollingService.cs:361-368
  • 问题: 逐点读取,20个模拟量=20次网络请求
  • 修复: 按地址分组,使用批量读取
  • 预期收益: 网络开销大幅降低

🟢 低优先级(代码质量)

任务10: ViewModel过度属性通知

  • 文件: src/YZWater.Core/ViewModels/ViewAViewModel.cs:268-320
  • 问题: 每次PLC更新(1Hz)触发30+个PropertyChanged,不管值是否变化
  • 修复: 赋值前比较新旧值,仅在值变化时通知

任务11: WebSocket MemoryStream分配

  • 文件: HubServer.cs:232-250、HubClient.cs:283-296
  • 问题: 每条消息 new MemoryStream()
  • 修复: 使用 ArrayPool<byte> 复用缓冲区

任务12: 日志优化

  • 文件: src/YZWater.Core/Services/LogService.cs:20,22
  • 问题: Debug级别过高 + 同步文件写入
  • 修复: 生产环境改为 Information,添加 buffered: true

执行顺序

按优先级从高到低逐个执行:

  1. 任务1~4(UI渲染优化)
  2. 任务5~6(内存泄漏修复)
  3. 任务7~9(数据层优化)
  4. 任务10~12(代码质量优化)

每个任务完成后立即 dotnet build 验证编译通过。


完成后归档

所有问题点和修复记录归档至本目录 (docs/)。