ThreatSourceLibaray/docs/project/csharp_performance_optimization_plan.md

15 KiB
Raw Permalink Blame History

C# 威胁源仿真库性能优化方案

文档信息

  • 创建日期: 2024年12月
  • 版本: 1.0
  • 目标: 解决C#运行时GC停顿和性能瓶颈问题

项目性能现状分析

代码规模统计

  • C#源文件: 75个
  • 代码总行数: 约23,621行
  • 核心类数量: 120+个
  • 主要性能热点: 10个关键模块

性能瓶颈识别

🔴 高优先级问题(严重影响)

1. SimulationManager内存分配风暴

问题位置: ThreatSource/src/Simulation/SimulationManager.cs:145-191

// 当前问题代码
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

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

var handlers = actualHandlers.ToList();  // 防御性复制
var handlers = typeHandlers.ToList();    // 防御性复制

性能影响: 每次事件发布都创建处理器列表副本

🟡 中优先级问题(中等影响)

4. 制导系统历史队列管理

问题位置: 多个制导系统类

private readonly Queue<bool> activeDetectionHistory = new();
private readonly Queue<double> lockSnrHistory = new();
// 频繁的Enqueue/Dequeue操作
5. 字符串操作性能问题

问题位置: 多个ToString()方法

// ElementStatusInfo.cs:57
string extendedInfo = string.Join(", ", ExtendedProperties.Select(p => 
    $"{p.Key}={valueStr}"));
6. 装箱拆箱问题

问题位置: ThreatSource/src/Equipment/EquipmentProperties.cs:41

public object Value { get; set; } = 0.0;  // 装箱问题
public Dictionary<string, ParameterValue> CustomParameters { get; set; }

详细优化方案

第一阶段内存管理优化预期性能提升40-60%

方案1.1SimulationManager对象池化

// 新增:对象池管理器
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:红外图像处理优化

// 新增:图像处理对象池
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:事件系统零分配优化

// 优化的事件发布方法
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:制导系统历史数据优化

// 使用循环缓冲区替代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:字符串操作优化

// 使用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:消除装箱拆箱

// 泛型参数值类
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.1SIMD向量化计算

// 向量化的距离计算
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:内存预分配策略

// 仿真管理器预分配策略
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.1Debug输出优化

// 条件编译和高性能日志
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:配置驱动的性能调优

// 性能配置类
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某些优化技术需要调整或替换。

性能测试

  dotnet test --configuration Release --filter "RunPerformanceTest" --verbosity detailed --logger "console;verbosity=detailed"