Files
esengine/docs/performance.md
2025-06-07 21:28:31 +08:00

6.3 KiB
Raw Blame History

ECS框架性能基准

本文档展示了ECS框架的真实性能数据和瓶颈分析。

🚀 快速测试

# 在项目根目录运行
node benchmark.js

📊 性能基准数据

测试环境: Node.js, 现代桌面CPU 测试时间: 2025年

1. 实体创建性能

实体数量 创建时间 创建速度 每个实体耗时
1,000 1.11ms 903,751个/秒 0.0011ms
5,000 3.47ms 1,441,462个/秒 0.0007ms
10,000 6.91ms 1,446,341个/秒 0.0007ms
20,000 7.44ms 2,686,764个/秒 0.0004ms
50,000 22.73ms 2,199,659个/秒 0.0005ms

结论: 实体创建性能优秀,平均每秒可创建 220万+个实体

2. 组件访问性能

迭代次数 总耗时 访问速度 每次访问耗时
100次 13.27ms 37,678,407次/秒 0.027μs
500次 34.27ms 72,957,553次/秒 0.014μs
1000次 68.85ms 72,624,911次/秒 0.014μs
2000次 139.67ms 71,598,669次/秒 0.014μs

结论: 组件访问性能优秀,平均每秒可访问 7200万+次

3. 组件操作性能

迭代次数 总耗时 操作速度 每次操作耗时
100次 36.89ms 27,105,193次/秒 0.037μs
500次 147.42ms 33,915,665次/秒 0.029μs
1000次 289.66ms 34,522,936次/秒 0.029μs

结论: 组件添加/删除性能优秀,平均每秒可操作 3450万+次

4. 查询系统性能

4.1 单组件查询

查询次数 总耗时 查询速度 每次查询耗时
100次 10.37ms 9,639次/秒 0.104ms
500次 41.17ms 12,144次/秒 0.082ms
1000次 82.11ms 12,178次/秒 0.082ms

4.2 多组件查询

查询次数 总耗时 查询速度 每次查询耗时
100次 11.22ms 8,914次/秒 0.112ms
500次 54.85ms 9,116次/秒 0.110ms
1000次 105.94ms 9,439次/秒 0.106ms

4.3 复合查询 (组件+标签)

查询次数 总耗时 查询速度 每次查询耗时
100次 15.80ms 6,327次/秒 0.158ms
500次 65.77ms 7,602次/秒 0.132ms
1000次 135.01ms 7,407次/秒 0.135ms

结论: ⚠️ 查询性能正常,平均每秒可查询 12000+次

5. 性能极限测试

实体数量 创建时间 处理时间/帧 FPS 状态
10,000 1.55ms 0.137ms 7264.0
25,000 3.91ms 0.432ms 2311.4
50,000 12.40ms 1.219ms 820.0
100,000 58.93ms 2.976ms 335.9
200,000 51.43ms 6.031ms 165.8

结论: 🚀 框架极限性能优秀,可处理 20万个实体@165.8FPS 仍维持高性能

🎯 性能瓶颈分析

主要瓶颈

  1. 查询系统 (相对瓶颈)

    • 单组件查询: ~12,000次/秒
    • 多组件查询: ~9,400次/秒
    • 复合查询: ~7,400次/秒
    • 原因: 需要遍历所有实体进行过滤
  2. 大规模实体处理 (可接受)

    • 10万个实体: 335.9 FPS
    • 20万个实体: 165.8 FPS
    • 原因: 线性时间复杂度,符合预期

非瓶颈项

实体创建: 220万+个/秒,性能优秀
组件访问: 7200万+次/秒,性能优秀
组件操作: 3450万+次/秒,性能优秀
系统处理: 20万个实体@165.8FPS,性能优秀

📈 时间复杂度分析

操作类型 时间复杂度 性能等级 说明
实体创建 O(1) 优秀 常数时间创建
组件访问 O(1) 优秀 哈希表查找
组件操作 O(1) 优秀 常数时间添加/删除
单组件查询 O(n) ⚠️ 正常 线性遍历实体
多组件查询 O(n×m) ⚠️ 正常 遍历实体×组件数
系统处理 O(n) 优秀 线性处理实体

💡 性能优化建议

对于查询密集型应用

  1. 缓存查询结果

    // 缓存常用查询
    const cachedPlayers = scene.getEntitiesWithComponents([Position, Player]);
    
  2. 减少查询频率

    // 每5帧查询一次而不是每帧
    if (frameCount % 5 === 0) {
        updateEnemyList();
    }
    
  3. 使用更精确的查询

    // 优先使用单组件查询
    const entities = scene.getEntitiesWithComponent(Position);
    

对于大规模实体应用

  1. 分批处理

    // 分批处理大量实体
    const batchSize = 1000;
    for (let i = 0; i < entities.length; i += batchSize) {
        processBatch(entities.slice(i, i + batchSize));
    }
    
  2. LOD系统

    // 根据距离调整处理频率
    if (distance > 100) {
        if (frameCount % 10 !== 0) continue; // 远距离实体降低更新频率
    }
    

🌍 实际应用指南

不同平台的建议

平台 推荐实体数量 查询频率 备注
桌面端 ≤100,000 高频查询可接受 性能充足
Web端 ≤50,000 中等查询频率 考虑浏览器限制
移动端 ≤20,000 低频查询 性能和电池优化

游戏类型建议

游戏类型 典型实体数 主要瓶颈 优化重点
2D平台游戏 1,000-5,000 无明显瓶颈 专注游戏逻辑
2D射击游戏 5,000-20,000 碰撞检测 空间分割算法
RTS游戏 10,000-50,000 查询系统 缓存+分批处理
MMO游戏 50,000+ 网络+查询 分区+优化查询

🔬 测试方法

运行完整基准测试

# 项目根目录
node benchmark.js

自定义测试

// 在source目录下
npm run test:framework:benchmark

📝 测试环境

  • Node.js版本: 16+
  • TypeScript版本: 5.8.3
  • 测试实体数: 5,000个 (带position、velocity组件)
  • 测试迭代: 多次取平均值
  • 硬件: 现代桌面CPU

结论: ECS框架本身性能优秀能够满足大多数应用需求。性能瓶颈主要来自于业务逻辑的算法选择而非框架架构。