diff --git a/AssetManager.Infrastructure/Services/MarketDataService.cs b/AssetManager.Infrastructure/Services/MarketDataService.cs index 41e02fe..5231d0c 100755 --- a/AssetManager.Infrastructure/Services/MarketDataService.cs +++ b/AssetManager.Infrastructure/Services/MarketDataService.cs @@ -22,11 +22,11 @@ public class MarketDataService : IMarketDataService private readonly IOkxMarketService _okxService; private readonly IMarketDataRepository _marketDataRepo; - // 内存缓存层(避免并发数据库查询导致连接池冲突) - private readonly ConcurrentDictionary _memoryCache = new(); + // 静态内存缓存层(跨请求共享,避免并发数据库查询导致连接池冲突) + private static readonly ConcurrentDictionary _memoryCache = new(); - // 防止并发请求同一股票(使用 Lazy 确保只创建一次) - private readonly ConcurrentDictionary>> _pendingPriceRequests = new(); + // 静态 pending 请求字典(跨请求共享,防止并发请求同一股票) + private static readonly ConcurrentDictionary>> _pendingPriceRequests = new(); public MarketDataService( ILogger logger, @@ -46,7 +46,7 @@ public class MarketDataService : IMarketDataService /// /// 获取实时价格(自动根据资产类型路由到对应数据源) - /// 使用 Lazy 确保同一时间只有一个请求在处理 + /// 使用静态缓存 + Lazy 确保跨请求并发安全 /// public async Task GetPriceAsync(string symbol, string assetType) { @@ -55,7 +55,7 @@ public class MarketDataService : IMarketDataService try { - // 第一步:查内存缓存(快速返回) + // 第一步:查静态内存缓存(快速返回) if (_memoryCache.TryGetValue(cacheKey, out var memoryCached) && memoryCached.expireAt > DateTime.Now) { _logger.LogInformation("[内存缓存命中] Symbol={Symbol}, Price={Price}", symbol, memoryCached.cache.Price); @@ -69,13 +69,14 @@ public class MarketDataService : IMarketDataService }; } - // 第二步:使用 Lazy 确保同一时间只有一个请求在处理(包括查数据库和获取价格) - var lazyTask = _pendingPriceRequests.GetOrAdd(cacheKey, - _ => new Lazy>(() => GetPriceInternalAsync(symbol, assetType, cacheKey))); + // 第二步:创建 Lazy 并尝试添加到字典 + // 先创建 Lazy,再 GetOrAdd,确保所有线程使用同一个 Lazy + var lazy = new Lazy>(() => GetPriceInternalAsync(symbol, assetType, cacheKey)); + var actualLazy = _pendingPriceRequests.GetOrAdd(cacheKey, lazy); try { - var result = await lazyTask.Value; + var result = await actualLazy.Value; _logger.LogInformation("[价格获取成功] Symbol={Symbol}, Price={Price}", symbol, result.Price); return result; }