NavisworksTransport/src/PathPlanning/GridMapCache.cs

347 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace NavisworksTransport.PathPlanning
{
/// <summary>
/// GridMap缓存项包含网格地图和访问时间信息
/// </summary>
public class GridMapCacheItem
{
/// <summary>
/// 缓存的网格地图
/// </summary>
public GridMap GridMap { get; set; }
/// <summary>
/// 最后访问时间
/// </summary>
public DateTime LastAccessTime { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedTime { get; set; }
/// <summary>
/// 访问次数
/// </summary>
public int AccessCount { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public GridMapCacheItem(GridMap gridMap)
{
GridMap = gridMap ?? throw new ArgumentNullException(nameof(gridMap));
LastAccessTime = DateTime.Now;
CreatedTime = DateTime.Now;
AccessCount = 1;
}
/// <summary>
/// 记录访问
/// </summary>
public void RecordAccess()
{
LastAccessTime = DateTime.Now;
AccessCount++;
}
}
/// <summary>
/// GridMap缓存统计信息
/// </summary>
public class GridMapCacheStatistics
{
/// <summary>
/// 缓存命中次数
/// </summary>
public long HitCount { get; set; }
/// <summary>
/// 缓存未命中次数
/// </summary>
public long MissCount { get; set; }
/// <summary>
/// 当前缓存项数量
/// </summary>
public int CurrentCount { get; set; }
/// <summary>
/// 最大缓存项数量
/// </summary>
public int MaxCapacity { get; set; }
/// <summary>
/// 被驱逐的缓存项数量
/// </summary>
public long EvictedCount { get; set; }
/// <summary>
/// 累计节省的构建时间(毫秒)
/// </summary>
public long TotalTimeSavedMs { get; set; }
/// <summary>
/// 缓存命中率
/// </summary>
public double HitRate => HitCount + MissCount > 0 ? (double)HitCount / (HitCount + MissCount) : 0.0;
/// <summary>
/// 缓存使用率
/// </summary>
public double UsageRate => MaxCapacity > 0 ? (double)CurrentCount / MaxCapacity : 0.0;
/// <summary>
/// 重置统计信息
/// </summary>
public void Reset()
{
HitCount = 0;
MissCount = 0;
EvictedCount = 0;
TotalTimeSavedMs = 0;
}
/// <summary>
/// 生成统计报告
/// </summary>
public string GenerateReport()
{
return $"GridMap缓存统计 - 命中率: {HitRate:P2} ({HitCount}命中/{MissCount}未命中), " +
$"使用率: {UsageRate:P2} ({CurrentCount}/{MaxCapacity}), " +
$"驱逐次数: {EvictedCount}, 节省时间: {TotalTimeSavedMs/1000.0:F1}秒";
}
}
/// <summary>
/// GridMap缓存管理器
/// 使用LRU策略管理GridMap缓存支持线程安全访问
/// </summary>
public class GridMapCache
{
private readonly ConcurrentDictionary<GridMapCacheKey, GridMapCacheItem> _cache;
private readonly object _cleanupLock = new object();
private readonly int _maxCapacity;
private readonly GridMapCacheStatistics _statistics;
/// <summary>
/// 获取缓存统计信息
/// </summary>
public GridMapCacheStatistics Statistics => _statistics;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="maxCapacity">最大缓存容量默认10个GridMap</param>
public GridMapCache(int maxCapacity = 10)
{
if (maxCapacity <= 0)
throw new ArgumentException("缓存容量必须大于0", nameof(maxCapacity));
_maxCapacity = maxCapacity;
_cache = new ConcurrentDictionary<GridMapCacheKey, GridMapCacheItem>();
_statistics = new GridMapCacheStatistics { MaxCapacity = maxCapacity };
LogManager.Info($"[GridMap缓存] 初始化完成,最大容量: {_maxCapacity}");
}
/// <summary>
/// 获取缓存的GridMap
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="estimatedBuildTimeMs">预估的构建时间(用于统计节省时间)</param>
/// <returns>GridMap对象如果不存在则返回null</returns>
public GridMap Get(GridMapCacheKey key, long estimatedBuildTimeMs = 0)
{
if (key == null)
return null;
if (_cache.TryGetValue(key, out var item))
{
// 记录访问
item.RecordAccess();
_statistics.HitCount++;
// 累计节省时间
if (estimatedBuildTimeMs > 0)
{
_statistics.TotalTimeSavedMs += estimatedBuildTimeMs;
}
LogManager.Info($"[GridMap缓存] 命中 - {key},访问次数: {item.AccessCount}");
return item.GridMap;
}
_statistics.MissCount++;
LogManager.Info($"[GridMap缓存] 未命中 - {key}");
return null;
}
/// <summary>
/// 添加GridMap到缓存
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="gridMap">GridMap对象</param>
public void Put(GridMapCacheKey key, GridMap gridMap)
{
if (key == null || gridMap == null)
return;
var item = new GridMapCacheItem(gridMap);
// 添加或更新缓存项
_cache.AddOrUpdate(key, item, (k, existing) =>
{
LogManager.Debug($"[GridMap缓存] 更新现有项 - {key}");
return item;
});
// 更新统计信息
_statistics.CurrentCount = _cache.Count;
LogManager.Info($"[GridMap缓存] 添加 - {key},当前容量: {_cache.Count}/{_maxCapacity}");
LogManager.Info($"[GridMap缓存] GridMap统计: {gridMap.GetStatistics()}");
// 检查是否需要清理
if (_cache.Count > _maxCapacity)
{
CleanupCache();
}
}
/// <summary>
/// 检查缓存中是否包含指定键
/// </summary>
/// <param name="key">缓存键</param>
/// <returns>是否包含</returns>
public bool ContainsKey(GridMapCacheKey key)
{
return key != null && _cache.ContainsKey(key);
}
/// <summary>
/// 清除所有缓存
/// </summary>
public void Clear()
{
lock (_cleanupLock)
{
var count = _cache.Count;
_cache.Clear();
_statistics.CurrentCount = 0;
_statistics.Reset();
LogManager.Info($"[GridMap缓存] 清除所有缓存,共清除 {count} 项");
}
}
/// <summary>
/// 获取缓存的所有键
/// </summary>
/// <returns>键列表</returns>
public IList<GridMapCacheKey> GetKeys()
{
return _cache.Keys.ToList();
}
/// <summary>
/// 清理缓存使用LRU策略移除最少使用的项
/// </summary>
private void CleanupCache()
{
lock (_cleanupLock)
{
// 双重检查,避免重复清理
if (_cache.Count <= _maxCapacity)
return;
var targetCount = Math.Max(1, (int)(_maxCapacity * 0.7)); // 清理到70%容量
var itemsToRemove = _cache.Count - targetCount;
LogManager.Info($"[GridMap缓存] 开始LRU清理当前: {_cache.Count},目标: {targetCount},需移除: {itemsToRemove}");
// 按最后访问时间排序,移除最久未访问的项
var sortedItems = _cache
.OrderBy(kvp => kvp.Value.LastAccessTime)
.ThenBy(kvp => kvp.Value.AccessCount) // 相同时间的情况下,优先移除访问次数少的
.Take(itemsToRemove)
.ToList();
int removedCount = 0;
foreach (var item in sortedItems)
{
if (_cache.TryRemove(item.Key, out _))
{
removedCount++;
_statistics.EvictedCount++;
LogManager.Debug($"[GridMap缓存] 移除 - {item.Key},最后访问: {item.Value.LastAccessTime:yyyy-MM-dd HH:mm:ss}");
}
}
_statistics.CurrentCount = _cache.Count;
LogManager.Info($"[GridMap缓存] LRU清理完成实际移除: {removedCount},当前容量: {_cache.Count}");
}
}
/// <summary>
/// 生成缓存详细报告
/// </summary>
/// <returns>报告字符串</returns>
public string GenerateDetailedReport()
{
var report = new System.Text.StringBuilder();
report.AppendLine(_statistics.GenerateReport());
if (_cache.Count > 0)
{
report.AppendLine($"\n当前缓存项详情:");
var sortedItems = _cache
.OrderByDescending(kvp => kvp.Value.LastAccessTime)
.Take(5) // 只显示最近5项
.ToList();
foreach (var item in sortedItems)
{
var gridStats = item.Value.GridMap?.GetStatistics() ?? "N/A";
report.AppendLine($" {item.Key}");
report.AppendLine($" 访问{item.Value.AccessCount}次,最后访问: {item.Value.LastAccessTime:MM-dd HH:mm:ss}");
report.AppendLine($" GridMap: {gridStats}");
}
if (_cache.Count > 5)
{
report.AppendLine($" ... 还有 {_cache.Count - 5} 项");
}
}
return report.ToString();
}
}
/// <summary>
/// 全局GridMap缓存管理器单例
/// </summary>
public static class GlobalGridMapCache
{
private static readonly Lazy<GridMapCache> _instance = new Lazy<GridMapCache>(() => new GridMapCache());
/// <summary>
/// 获取全局缓存实例
/// </summary>
public static GridMapCache Instance => _instance.Value;
/// <summary>
/// 重置全局缓存(主要用于测试)
/// </summary>
public static void Reset()
{
_instance.Value.Clear();
}
}
}