289 lines
7.7 KiB
Markdown
289 lines
7.7 KiB
Markdown
# 自动路径规划网格生成性能优化方案
|
||
|
||
## 当前性能问题
|
||
|
||
- 1万个模型,网格大小0.25m时需要5秒
|
||
- 更大模型或更小网格时性能急剧下降
|
||
|
||
## 性能瓶颈分析
|
||
|
||
### 1. 空间索引构建阶段 (BuildSpatialHashIndex)
|
||
|
||
- 需要遍历所有模型项(1万个)计算边界框
|
||
- 每个模型项都要计算空间哈希键并添加到对应桶中
|
||
- 固定的空间哈希大小(10m)可能导致分布不均
|
||
|
||
### 2. 垂直扫描阶段 (ParallelScanHeightIntervals) - **最大瓶颈**
|
||
|
||
- 对每个网格点(网格0.25m时,数量巨大)执行:
|
||
- GetCandidateItemsFromSpatialHash: 查询9个相邻哈希桶
|
||
- HeightFiltering: 高度范围筛选
|
||
- PerformIntersectionTests: 对筛选后的每个模型项进行包围盒相交测试
|
||
- 虽然使用了包围盒快速检测而非射线法,但重复查询和测试量仍然巨大
|
||
|
||
### 3. 关键问题
|
||
|
||
- 空间哈希粒度固定(10m),对于0.25m的网格太粗糙,导致每个桶内模型项过多
|
||
- 每个网格点都要查询9个哈希桶,产生大量重复
|
||
- HashSet去重和ToList转换带来额外开销
|
||
|
||
## 优化方案
|
||
|
||
### 第一阶段:空间索引优化(预期提升40-60%)
|
||
|
||
#### 1.1 自适应空间哈希大小
|
||
|
||
```csharp
|
||
// 根据网格大小动态调整空间哈希大小
|
||
// 当前固定10m,改为根据网格大小动态计算
|
||
_spatialHashSize = Math.Max(gridSize * 4, 2.0); // 例如:0.25m网格用1m哈希桶
|
||
```
|
||
|
||
#### 1.2 优化哈希键查询策略
|
||
|
||
- 对于小网格,减少查询的相邻桶数量(从9个减到4个或1个)
|
||
- 实现基于模型大小的智能查询范围
|
||
|
||
```csharp
|
||
private List<string> GetSpatialHashKeysForPoint(Point3D point, double searchRadius)
|
||
{
|
||
var keys = new List<string>();
|
||
int centerX = (int)Math.Floor(point.X / _spatialHashSize);
|
||
int centerY = (int)Math.Floor(point.Y / _spatialHashSize);
|
||
|
||
// 根据搜索半径动态确定查询范围
|
||
int range = (int)Math.Ceiling(searchRadius / _spatialHashSize);
|
||
range = Math.Min(range, 1); // 限制最大查询范围
|
||
|
||
for (int dx = -range; dx <= range; dx++)
|
||
{
|
||
for (int dy = -range; dy <= range; dy++)
|
||
{
|
||
keys.Add($"{centerX + dx},{centerY + dy}");
|
||
}
|
||
}
|
||
return keys;
|
||
}
|
||
```
|
||
|
||
#### 1.3 缓存优化
|
||
|
||
- 为相邻网格点缓存候选模型列表
|
||
- 实现LRU缓存减少重复查询
|
||
|
||
```csharp
|
||
private readonly Dictionary<string, List<ModelItem>> _candidateCache =
|
||
new Dictionary<string, List<ModelItem>>();
|
||
|
||
private List<ModelItem> GetCandidateItemsFromSpatialHashWithCache(Point3D point)
|
||
{
|
||
string cacheKey = $"{(int)(point.X/_spatialHashSize)},{(int)(point.Y/_spatialHashSize)}";
|
||
|
||
if (_candidateCache.TryGetValue(cacheKey, out var cached))
|
||
return cached;
|
||
|
||
var candidates = GetCandidateItemsFromSpatialHash(point);
|
||
_candidateCache[cacheKey] = candidates;
|
||
return candidates;
|
||
}
|
||
```
|
||
|
||
### 第二阶段:数据结构优化(预期提升20-30%)
|
||
|
||
#### 2.1 避免不必要的数据转换
|
||
|
||
```csharp
|
||
// 直接返回IEnumerable而非ToList()
|
||
private IEnumerable<ModelItem> GetCandidateItemsFromSpatialHash(Point3D point)
|
||
{
|
||
var hashKeys = GetSpatialHashKeysForPoint(point);
|
||
|
||
foreach (var key in hashKeys)
|
||
{
|
||
if (_spatialHashMap.TryGetValue(key, out var items))
|
||
{
|
||
foreach (var item in items)
|
||
yield return item;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2.2 使用对象池
|
||
|
||
```csharp
|
||
// 为HashSet<ModelItem>实现对象池
|
||
private readonly ObjectPool<HashSet<ModelItem>> _hashSetPool =
|
||
new ObjectPool<HashSet<ModelItem>>(
|
||
() => new HashSet<ModelItem>(),
|
||
set => set.Clear());
|
||
```
|
||
|
||
#### 2.3 批处理相邻点
|
||
|
||
```csharp
|
||
// 将相邻的网格点分组处理,共享候选列表
|
||
private void ProcessGridPointBatch(List<Point3D> batch)
|
||
{
|
||
// 计算批次的边界框
|
||
var batchBounds = CalculateBounds(batch);
|
||
|
||
// 一次性获取所有候选项
|
||
var candidates = GetCandidatesForBounds(batchBounds);
|
||
|
||
// 为批次中的每个点处理
|
||
Parallel.ForEach(batch, point =>
|
||
{
|
||
ProcessPointWithCandidates(point, candidates);
|
||
});
|
||
}
|
||
```
|
||
|
||
### 第三阶段:算法优化(预期提升15-25%)
|
||
|
||
#### 3.1 分层扫描策略
|
||
|
||
```csharp
|
||
// 先用粗网格(如1m)快速识别障碍物区域
|
||
var coarseGrid = GenerateCoarseGrid(1.0);
|
||
var obstacleRegions = IdentifyObstacleRegions(coarseGrid);
|
||
|
||
// 只在边界区域使用细网格(0.25m)
|
||
var fineGridPoints = GenerateFineGridPoints(obstacleRegions, 0.25);
|
||
```
|
||
|
||
#### 3.2 早期终止优化
|
||
|
||
```csharp
|
||
private List<ModelItem> HeightFiltering(List<ModelItem> items, double minZ, double maxZ)
|
||
{
|
||
var filtered = new List<ModelItem>();
|
||
int fullyBlockedCount = 0;
|
||
|
||
foreach (var item in items)
|
||
{
|
||
var bbox = item.BoundingBox();
|
||
|
||
// 如果完全覆盖扫描范围,标记并早期终止
|
||
if (bbox.Min.Z <= minZ && bbox.Max.Z >= maxZ)
|
||
{
|
||
fullyBlockedCount++;
|
||
if (fullyBlockedCount > 3) // 多个障碍物完全覆盖
|
||
{
|
||
return items; // 早期返回,无需继续筛选
|
||
}
|
||
}
|
||
|
||
if (bbox.Max.Z >= minZ && bbox.Min.Z <= maxZ)
|
||
{
|
||
filtered.Add(item);
|
||
}
|
||
}
|
||
|
||
return filtered;
|
||
}
|
||
```
|
||
|
||
#### 3.3 空间局部性优化
|
||
|
||
```csharp
|
||
// 按空间顺序处理网格点,提高缓存命中率
|
||
var sortedPoints = gridPoints
|
||
.OrderBy(p => p.Y)
|
||
.ThenBy(p => p.X)
|
||
.ToList();
|
||
```
|
||
|
||
### 第四阶段:并行优化(预期提升10-20%)
|
||
|
||
#### 4.1 优化并行粒度
|
||
|
||
```csharp
|
||
// 使用Partitioner创建更均衡的工作负载
|
||
var partitioner = Partitioner.Create(pointsList, true);
|
||
Parallel.ForEach(partitioner, new ParallelOptions
|
||
{
|
||
MaxDegreeOfParallelism = _parallelDegree
|
||
},
|
||
gridPoint =>
|
||
{
|
||
// 处理逻辑
|
||
});
|
||
```
|
||
|
||
#### 4.2 减少锁竞争
|
||
|
||
```csharp
|
||
// 使用线程本地存储减少共享资源访问
|
||
ThreadLocal<List<IntersectionResult>> threadLocalResults =
|
||
new ThreadLocal<List<IntersectionResult>>(() => new List<IntersectionResult>());
|
||
```
|
||
|
||
## 实施计划
|
||
|
||
### 立即实施(1-2天)
|
||
|
||
1. 自适应空间哈希大小
|
||
2. 优化哈希键查询策略
|
||
3. 避免不必要的ToList()转换
|
||
|
||
### 短期实施(3-5天)
|
||
|
||
1. 实现缓存机制
|
||
2. 批处理相邻点
|
||
3. 优化并行粒度
|
||
|
||
### 中期实施(1-2周)
|
||
|
||
1. 分层扫描策略
|
||
2. 对象池实现
|
||
3. 早期终止优化
|
||
|
||
## 预期效果
|
||
|
||
| 场景 | 当前性能 | 优化后性能 | 提升比例 |
|
||
|------|---------|-----------|---------|
|
||
| 1万模型,0.25m网格 | 5秒 | 1.5-2秒 | 2.5-3倍 |
|
||
| 2万模型,0.25m网格 | 15-20秒 | 3-5秒 | 4-5倍 |
|
||
| 1万模型,0.1m网格 | 30秒+ | 5-8秒 | 4-6倍 |
|
||
|
||
## 关键代码修改文件
|
||
|
||
1. **src/PathPlanning/VerticalScanProcessor.cs**
|
||
- 构造函数:添加网格大小参数
|
||
- GetSpatialHashKeysForPoint:智能查询范围
|
||
- GetCandidateItemsFromSpatialHash:缓存实现
|
||
- ParallelScanHeightIntervals:批处理优化
|
||
|
||
2. **src/PathPlanning/GridMapGenerator.cs**
|
||
- GenerateChannelBased2_5D:传递网格大小到VerticalScanProcessor
|
||
|
||
3. **src/PathPlanning/ChannelBasedGridBuilder.cs**
|
||
- BuildChannelCoverage:优化通道识别流程
|
||
|
||
## 测试验证
|
||
|
||
1. **性能测试**
|
||
- 不同模型数量(1千、5千、1万、2万)
|
||
- 不同网格大小(1m、0.5m、0.25m、0.1m)
|
||
- 记录时间和内存使用
|
||
|
||
2. **正确性验证**
|
||
- 对比优化前后的网格生成结果
|
||
- 确保路径规划结果一致
|
||
|
||
3. **稳定性测试**
|
||
- 长时间运行测试
|
||
- 内存泄漏检测
|
||
|
||
## 风险评估
|
||
|
||
1. **缓存可能导致内存增加**
|
||
- 解决方案:实现LRU缓存,限制缓存大小
|
||
|
||
2. **并行度提高可能导致CPU占用过高**
|
||
- 解决方案:提供可配置的并行度参数
|
||
|
||
3. **空间哈希大小改变可能影响结果**
|
||
- 解决方案:充分测试,确保结果一致性
|