502 lines
15 KiB
Markdown
502 lines
15 KiB
Markdown
# C# 威胁源仿真库性能优化方案
|
||
|
||
## 文档信息
|
||
- **创建日期**: 2024年12月
|
||
- **版本**: 1.0
|
||
- **目标**: 解决C#运行时GC停顿和性能瓶颈问题
|
||
|
||
## 项目性能现状分析
|
||
|
||
### 代码规模统计
|
||
- **C#源文件**: 75个
|
||
- **代码总行数**: 约23,621行
|
||
- **核心类数量**: 120+个
|
||
- **主要性能热点**: 10个关键模块
|
||
|
||
### 性能瓶颈识别
|
||
|
||
#### 🔴 高优先级问题(严重影响)
|
||
|
||
##### 1. SimulationManager内存分配风暴
|
||
**问题位置**: `ThreatSource/src/Simulation/SimulationManager.cs:145-191`
|
||
```csharp
|
||
// 当前问题代码
|
||
List<SimulationElement> activeElements = entities.Values
|
||
.Cast<SimulationElement>()
|
||
.Where(e => e.IsActive)
|
||
.ToList();
|
||
|
||
var activeMissiles = entities.Values.OfType<BaseMissile>().Where(e => e.IsActive).ToList();
|
||
var activeTargets = entities.Values.OfType<Tank>().Where(e => e.IsActive).ToList();
|
||
```
|
||
**性能影响**: 每帧分配3个大型List,约300-1000个对象,触发Gen0/Gen1 GC
|
||
|
||
##### 2. 红外图像处理大量临时对象
|
||
**问题位置**: `ThreatSource/src/Guidance/InfraredTargetRecognizer.cs:159-228`
|
||
```csharp
|
||
List<Blob> blobs = new List<Blob>();
|
||
Queue<(int x, int y)> queue = new Queue<(int x, int y)>();
|
||
List<Blob> filteredBlobs = [];
|
||
```
|
||
**性能影响**: 每次图像处理分配数百个临时对象和像素列表
|
||
|
||
##### 3. 事件系统频繁复制
|
||
**问题位置**: `ThreatSource/src/Simulation/SimulationManager.cs:268-317`
|
||
```csharp
|
||
var handlers = actualHandlers.ToList(); // 防御性复制
|
||
var handlers = typeHandlers.ToList(); // 防御性复制
|
||
```
|
||
**性能影响**: 每次事件发布都创建处理器列表副本
|
||
|
||
#### 🟡 中优先级问题(中等影响)
|
||
|
||
##### 4. 制导系统历史队列管理
|
||
**问题位置**: 多个制导系统类
|
||
```csharp
|
||
private readonly Queue<bool> activeDetectionHistory = new();
|
||
private readonly Queue<double> lockSnrHistory = new();
|
||
// 频繁的Enqueue/Dequeue操作
|
||
```
|
||
|
||
##### 5. 字符串操作性能问题
|
||
**问题位置**: 多个ToString()方法
|
||
```csharp
|
||
// ElementStatusInfo.cs:57
|
||
string extendedInfo = string.Join(", ", ExtendedProperties.Select(p =>
|
||
$"{p.Key}={valueStr}"));
|
||
```
|
||
|
||
##### 6. 装箱拆箱问题
|
||
**问题位置**: `ThreatSource/src/Equipment/EquipmentProperties.cs:41`
|
||
```csharp
|
||
public object Value { get; set; } = 0.0; // 装箱问题
|
||
public Dictionary<string, ParameterValue> CustomParameters { get; set; }
|
||
```
|
||
|
||
## 详细优化方案
|
||
|
||
### 第一阶段:内存管理优化(预期性能提升:40-60%)
|
||
|
||
#### 方案1.1:SimulationManager对象池化
|
||
```csharp
|
||
// 新增:对象池管理器
|
||
public class SimulationObjectPools
|
||
{
|
||
private readonly ObjectPool<List<SimulationElement>> _elementListPool;
|
||
private readonly ObjectPool<List<BaseMissile>> _missileListPool;
|
||
private readonly ObjectPool<List<Tank>> _tankListPool;
|
||
private readonly ObjectPool<List<(Tank, BaseMissile, double)>> _hitEventPool;
|
||
|
||
public SimulationObjectPools()
|
||
{
|
||
_elementListPool = new ObjectPool<List<SimulationElement>>(
|
||
createFunc: () => new List<SimulationElement>(1000),
|
||
resetAction: list => list.Clear(),
|
||
maximumRetained: 4
|
||
);
|
||
// 其他池的初始化...
|
||
}
|
||
|
||
public List<SimulationElement> GetElementList() => _elementListPool.Get();
|
||
public void ReturnElementList(List<SimulationElement> list) => _elementListPool.Return(list);
|
||
}
|
||
|
||
// 优化后的UpdateSimulation方法
|
||
private void UpdateSimulation(double deltaTime)
|
||
{
|
||
var activeElements = _objectPools.GetElementList();
|
||
try
|
||
{
|
||
lock (_lock)
|
||
{
|
||
foreach (var entity in entities.Values)
|
||
{
|
||
if (entity is SimulationElement element && element.IsActive)
|
||
{
|
||
activeElements.Add(element);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 使用预分配的列表更新实体
|
||
foreach (var element in activeElements)
|
||
{
|
||
try { element.Update(deltaTime); }
|
||
catch (Exception ex) { Debug.WriteLine($"更新实体 {element.Id} 时发生错误: {ex.Message}"); }
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
_objectPools.ReturnElementList(activeElements);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 方案1.2:红外图像处理优化
|
||
```csharp
|
||
// 新增:图像处理对象池
|
||
public class ImageProcessingPools
|
||
{
|
||
private readonly ObjectPool<List<Blob>> _blobListPool;
|
||
private readonly ObjectPool<Queue<(int, int)>> _pixelQueuePool;
|
||
private readonly ObjectPool<List<(int, int)>> _pixelListPool;
|
||
|
||
// 池化的图像分割方法
|
||
public List<Blob> PerformConnectedComponentAnalysis(InfraredImage image)
|
||
{
|
||
var blobs = _blobListPool.Get();
|
||
var queue = _pixelQueuePool.Get();
|
||
var pixelList = _pixelListPool.Get();
|
||
|
||
try
|
||
{
|
||
// 重用现有分析逻辑,但使用池化对象
|
||
// ... 具体实现
|
||
return new List<Blob>(blobs); // 返回副本
|
||
}
|
||
finally
|
||
{
|
||
_blobListPool.Return(blobs);
|
||
_pixelQueuePool.Return(queue);
|
||
_pixelListPool.Return(pixelList);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 方案1.3:事件系统零分配优化
|
||
```csharp
|
||
// 优化的事件发布方法
|
||
public void PublishEvent<T>(T evt) where T : class
|
||
{
|
||
if (evt == null) throw new ArgumentNullException(nameof(evt));
|
||
|
||
var eventType = typeof(T);
|
||
|
||
// 直接遍历,避免ToList()
|
||
if (eventHandlers.TryGetValue(eventType, out var handlers))
|
||
{
|
||
// 使用for循环而不是foreach,避免枚举器分配
|
||
for (int i = 0; i < handlers.Count; i++)
|
||
{
|
||
try
|
||
{
|
||
((Action<T>)handlers[i]).Invoke(evt);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.WriteLine($"[事件] 处理异常: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 第二阶段:算法和数据结构优化(预期性能提升:20-30%)
|
||
|
||
#### 方案2.1:制导系统历史数据优化
|
||
```csharp
|
||
// 使用循环缓冲区替代Queue
|
||
public struct CircularBuffer<T>
|
||
{
|
||
private readonly T[] _buffer;
|
||
private int _head;
|
||
private int _count;
|
||
|
||
public CircularBuffer(int capacity)
|
||
{
|
||
_buffer = new T[capacity];
|
||
_head = 0;
|
||
_count = 0;
|
||
}
|
||
|
||
public void Add(T item)
|
||
{
|
||
_buffer[(_head + _count) % _buffer.Length] = item;
|
||
if (_count < _buffer.Length) _count++;
|
||
else _head = (_head + 1) % _buffer.Length;
|
||
}
|
||
|
||
public double CalculateSuccessRate() where T : struct, IConvertible
|
||
{
|
||
if (_count == 0) return 0.0;
|
||
|
||
int successCount = 0;
|
||
for (int i = 0; i < _count; i++)
|
||
{
|
||
if (_buffer[(_head + i) % _buffer.Length].ToBoolean(null))
|
||
successCount++;
|
||
}
|
||
return (double)successCount / _count;
|
||
}
|
||
}
|
||
|
||
// 在制导系统中使用
|
||
private CircularBuffer<bool> _detectionHistory = new(TRACK_DETECTION_WINDOW_SIZE);
|
||
private CircularBuffer<double> _snrHistory = new(LOCK_SNR_WINDOW_SIZE);
|
||
```
|
||
|
||
#### 方案2.2:字符串操作优化
|
||
```csharp
|
||
// 使用StringBuilder和字符串池
|
||
public static class StringBuilderPool
|
||
{
|
||
private static readonly ObjectPool<StringBuilder> _pool = new ObjectPool<StringBuilder>(
|
||
createFunc: () => new StringBuilder(512),
|
||
resetAction: sb => sb.Clear(),
|
||
maximumRetained: Environment.ProcessorCount * 2
|
||
);
|
||
|
||
public static StringBuilder Get() => _pool.Get();
|
||
public static void Return(StringBuilder sb) => _pool.Return(sb);
|
||
}
|
||
|
||
// 优化的ToString方法
|
||
public override string ToString()
|
||
{
|
||
var sb = StringBuilderPool.Get();
|
||
try
|
||
{
|
||
sb.Append('[').Append(ElementType).Append("] Id=").Append(Id);
|
||
sb.Append(", Active=").Append(IsActive);
|
||
sb.Append(", 位置=").Append(KState.Position);
|
||
// ... 其他属性
|
||
|
||
if (ExtendedProperties.Count > 0)
|
||
{
|
||
sb.Append(", ");
|
||
bool first = true;
|
||
foreach (var kvp in ExtendedProperties)
|
||
{
|
||
if (!first) sb.Append(", ");
|
||
sb.Append(kvp.Key).Append('=');
|
||
FormatValue(sb, kvp.Value);
|
||
first = false;
|
||
}
|
||
}
|
||
|
||
return sb.ToString();
|
||
}
|
||
finally
|
||
{
|
||
StringBuilderPool.Return(sb);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 方案2.3:消除装箱拆箱
|
||
```csharp
|
||
// 泛型参数值类
|
||
public readonly struct ParameterValue<T> where T : struct
|
||
{
|
||
public readonly T Value;
|
||
public readonly string Unit;
|
||
public readonly string Category;
|
||
public readonly string Description;
|
||
|
||
public ParameterValue(T value, string unit = "", string category = "", string description = "")
|
||
{
|
||
Value = value;
|
||
Unit = unit ?? "";
|
||
Category = category ?? "";
|
||
Description = description ?? "";
|
||
}
|
||
}
|
||
|
||
// 类型安全的参数字典
|
||
public class TypedParameterDictionary
|
||
{
|
||
private readonly Dictionary<string, ParameterValue<double>> _doubleParams = new();
|
||
private readonly Dictionary<string, ParameterValue<int>> _intParams = new();
|
||
private readonly Dictionary<string, ParameterValue<bool>> _boolParams = new();
|
||
private readonly Dictionary<string, string> _stringParams = new();
|
||
|
||
public void SetDouble(string key, double value, string unit = "", string category = "")
|
||
{
|
||
_doubleParams[key] = new ParameterValue<double>(value, unit, category);
|
||
}
|
||
|
||
public T GetValue<T>(string key, T defaultValue = default) where T : struct
|
||
{
|
||
if (typeof(T) == typeof(double) && _doubleParams.TryGetValue(key, out var doubleParam))
|
||
return (T)(object)doubleParam.Value;
|
||
// 其他类型的处理...
|
||
return defaultValue;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 第三阶段:高级优化技术(预期性能提升:10-20%)
|
||
|
||
#### 方案3.1:SIMD向量化计算
|
||
```csharp
|
||
// 向量化的距离计算
|
||
public static void CalculateDistancesBatch(ReadOnlySpan<Vector3D> positions1,
|
||
ReadOnlySpan<Vector3D> positions2,
|
||
Span<double> results)
|
||
{
|
||
Debug.Assert(positions1.Length == positions2.Length);
|
||
Debug.Assert(results.Length >= positions1.Length);
|
||
|
||
for (int i = 0; i < positions1.Length; i++)
|
||
{
|
||
var delta = positions1[i] - positions2[i];
|
||
results[i] = delta.Magnitude();
|
||
}
|
||
}
|
||
|
||
// 向量化的RCS计算
|
||
public static void CalculateRcsBatch(ReadOnlySpan<double> distances,
|
||
ReadOnlySpan<double> rcsValues,
|
||
ReadOnlySpan<double> transmittances,
|
||
Span<double> snrResults)
|
||
{
|
||
// 使用System.Numerics.Vector进行SIMD优化
|
||
// ... 具体实现
|
||
}
|
||
```
|
||
|
||
#### 方案3.2:内存预分配策略
|
||
```csharp
|
||
// 仿真管理器预分配策略
|
||
public class PreallocatedSimulationManager
|
||
{
|
||
// 预分配常用大小的数组
|
||
private readonly double[] _tempDistances = new double[1000];
|
||
private readonly Vector3D[] _tempPositions = new Vector3D[1000];
|
||
private readonly bool[] _tempResults = new bool[1000];
|
||
|
||
// 使用ArrayPool for大型临时数组
|
||
private static readonly ArrayPool<double> _doubleArrayPool = ArrayPool<double>.Shared;
|
||
private static readonly ArrayPool<Vector3D> _vectorArrayPool = ArrayPool<Vector3D>.Create();
|
||
|
||
public void ProcessBatchOperations(int count)
|
||
{
|
||
double[] distances = count <= 1000 ? _tempDistances : _doubleArrayPool.Rent(count);
|
||
try
|
||
{
|
||
// 批量处理操作
|
||
}
|
||
finally
|
||
{
|
||
if (distances != _tempDistances)
|
||
_doubleArrayPool.Return(distances);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 第四阶段:专项优化
|
||
|
||
#### 方案4.1:Debug输出优化
|
||
```csharp
|
||
// 条件编译和高性能日志
|
||
public static class PerformanceLogger
|
||
{
|
||
[Conditional("DEBUG")]
|
||
public static void LogDebug(string message)
|
||
{
|
||
Debug.WriteLine(message);
|
||
}
|
||
|
||
// 格式化字符串的延迟计算
|
||
[Conditional("DEBUG")]
|
||
public static void LogDebugFormat<T1, T2>(string format, T1 arg1, T2 arg2)
|
||
{
|
||
Debug.WriteLine(format, arg1, arg2);
|
||
}
|
||
|
||
// 使用插值字符串处理程序(.NET 6+)
|
||
[Conditional("DEBUG")]
|
||
public static void LogDebugInterpolated([InterpolatedStringHandler] ref LogInterpolatedStringHandler handler)
|
||
{
|
||
Debug.WriteLine(handler.ToString());
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 方案4.2:配置驱动的性能调优
|
||
```csharp
|
||
// 性能配置类
|
||
public class PerformanceConfig
|
||
{
|
||
public bool EnableObjectPooling { get; set; } = true;
|
||
public bool EnableStringPooling { get; set; } = true;
|
||
public bool EnableBatchProcessing { get; set; } = true;
|
||
public int ObjectPoolMaxSize { get; set; } = 1000;
|
||
public int StringBuilderPoolSize { get; set; } = 100;
|
||
public bool EnableSIMD { get; set; } = true;
|
||
public bool EnableDebugLogging { get; set; } = false;
|
||
}
|
||
```
|
||
|
||
## 实施计划和时间估算
|
||
|
||
### 阶段1:基础内存优化(2-3周)
|
||
- **周1**: SimulationManager对象池化
|
||
- **周2**: 红外图像处理优化
|
||
- **周3**: 事件系统优化和测试
|
||
|
||
### 阶段2:算法优化(2-3周)
|
||
- **周4**: 制导系统历史数据优化
|
||
- **周5**: 字符串操作和装箱优化
|
||
- **周6**: 集成测试和性能验证
|
||
|
||
### 阶段3:高级优化(1-2周)
|
||
- **周7**: SIMD优化和内存预分配
|
||
- **周8**: 全面性能测试和调优
|
||
|
||
### 阶段4:验证和部署(1周)
|
||
- **周9**: 性能基准测试、文档更新
|
||
|
||
## 预期性能提升
|
||
|
||
### GC性能改善
|
||
- **Gen0 GC频率**: 减少60-80%
|
||
- **Gen1 GC频率**: 减少40-60%
|
||
- **GC停顿时间**: 减少50-70%
|
||
|
||
### 整体性能提升
|
||
- **仿真步进性能**: 提升40-60%
|
||
- **内存使用**: 减少30-50%
|
||
- **CPU占用**: 减少20-40%
|
||
|
||
### 具体指标预期
|
||
- **每帧内存分配**: 从~10MB降至~2MB
|
||
- **仿真FPS**: 从30-50提升至60-100
|
||
- **大规模场景支持**: 从100实体提升至500+实体
|
||
|
||
## 风险评估和缓解措施
|
||
|
||
### 主要风险
|
||
1. **代码复杂度增加**: 对象池和内存管理增加复杂性
|
||
2. **调试困难**: 优化后的代码可能难以调试
|
||
3. **兼容性问题**: 优化可能引入subtle bugs
|
||
|
||
### 缓解措施
|
||
1. **渐进式实施**: 每阶段独立验证
|
||
2. **性能测试套件**: 建立全面的性能回归测试
|
||
3. **配置开关**: 允许动态启用/禁用优化
|
||
4. **详细文档**: 记录所有优化决策和实现细节
|
||
|
||
## 成功标准
|
||
|
||
### 性能基准
|
||
- 1000实体仿真场景下稳定运行60FPS
|
||
- GC停顿时间<10ms
|
||
- 内存使用<1GB
|
||
|
||
### 质量标准
|
||
- 所有现有测试通过
|
||
- 新增性能测试覆盖率>90%
|
||
- 代码质量保持或提升
|
||
|
||
---
|
||
|
||
**注意**: 本优化方案需要.NET 6+支持。如使用较早版本的.NET Framework,某些优化技术需要调整或替换。
|
||
|
||
## 性能测试
|
||
|
||
```bash
|
||
dotnet test --configuration Release --filter "RunPerformanceTest" --verbosity detailed --logger "console;verbosity=detailed"
|
||
``` |