diff --git a/AssetManager.Infrastructure/Services/MarketDataService.cs b/AssetManager.Infrastructure/Services/MarketDataService.cs index d5e5206..cb281e0 100755 --- a/AssetManager.Infrastructure/Services/MarketDataService.cs +++ b/AssetManager.Infrastructure/Services/MarketDataService.cs @@ -2,6 +2,7 @@ using AssetManager.Data; using AssetManager.Data.Repositories; using AssetManager.Models.DTOs; using Microsoft.Extensions.Logging; +using System.Collections.Concurrent; namespace AssetManager.Infrastructure.Services; @@ -20,6 +21,9 @@ public class MarketDataService : IMarketDataService private readonly ITiingoMarketService _tiingoService; private readonly IOkxMarketService _okxService; private readonly IMarketDataRepository _marketDataRepo; + + // 防止并发请求同一股票 + private readonly ConcurrentDictionary> _pendingPriceRequests = new(); public MarketDataService( ILogger logger, @@ -39,9 +43,11 @@ public class MarketDataService : IMarketDataService /// /// 获取实时价格(自动根据资产类型路由到对应数据源) + /// 使用并发控制防止重复请求 /// public async Task GetPriceAsync(string symbol, string assetType) { + var cacheKey = $"{symbol.ToUpper()}_{assetType.ToUpper()}"; _logger.LogInformation("获取实时价格: {Symbol}, 资产类型: {AssetType}", symbol, assetType); // 先查缓存 @@ -60,7 +66,27 @@ public class MarketDataService : IMarketDataService }; } - // 缓存未命中,调用API + // 使用 GetOrAdd 模式防止并发重复请求 + var priceTask = _pendingPriceRequests.GetOrAdd(cacheKey, _ => FetchPriceFromSourceAsync(symbol, assetType)); + + try + { + return await priceTask; + } + finally + { + // 请求完成后移除(无论成功失败) + _pendingPriceRequests.TryRemove(cacheKey, out _); + } + } + + /// + /// 从数据源获取价格(内部方法) + /// + private async Task FetchPriceFromSourceAsync(string symbol, string assetType) + { + _logger.LogInformation("从数据源获取价格: {Symbol}, 资产类型: {AssetType}", symbol, assetType); + MarketPriceResponse response; string source;