有一个业务场景,接口的业务逻辑非常复杂,对数据库的压力比较大,希望限制下接口的并发数量,研究了下:
using Microsoft.AspNetCore.Mvc; using System.Collections.Concurrent; using System.Threading.Tasks; namespace TestBingFa.Controllers { [ApiController] [Route("[controller]/[action]")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; private static ConcurrentDictionary<string, long> _methodCallCounts = new ConcurrentDictionary<string, long>(); private static int num = 0; private static SemaphoreSlim globalSemaphore = new SemaphoreSlim(30); private static int num2 = 0; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet] public IEnumerable<WeatherForecast> GetWeatherForecast() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); } [HttpGet] public async Task<List<string>> GetWeatherForecast2() { var semaphore = new SemaphoreSlim(10); var tasks = new List<Task<string>>(); for (int i = 0; i < 20; i++) { if (i >= 10) { int b = i; } // 等待直到Semaphore允许进入 await semaphore.WaitAsync(); int localI = i; tasks.Add(Task.Run(async Task<string> () => { try { return await SimulateRemoteRequest(localI); } finally { // 完成任务后释放Semaphore semaphore.Release(); subNum(); } })); } // 等待所有任务完成 await Task.WhenAll(tasks); List<string> list = new List<string>(); foreach (var item in tasks) { list.Add(item.Result); } string msg = GetStatistics(); list.Add(msg); return list; } private async Task<string> SimulateRemoteRequest(int i) { _logger.LogInformation("task " + i + " started"+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); addNum(); // Simulate a delay to represent an IO-intensive operation await Task.Delay(10000); // Simulate a 2 second delay // Optionally, make a real HTTP request to simulate a remote call // var response = await _httpClient.GetAsync("https://example.com"); // var content = await response.Content.ReadAsStringAsync(); // For simulation purposes, we return a fixed message return "task " + i + " completed"; } private static readonly object _lock = new object(); private void addNum() { lock (_lock) { num = num + 1; _logger.LogInformation("num:" + num); } } private void subNum() { lock (_lock) { num = num - 1; _logger.LogInformation("num:" + num); } } private static void IncrementMethodCallCount(string methodName) { _methodCallCounts.AddOrUpdate(methodName, 1, (key, count) => count + 1); } private static void IncrementMethodCallCount2(string methodName) { _methodCallCounts.AddOrUpdate(methodName, 1, (key, count) => count -1); } private static string GetStatistics() { var stats = new System.Text.StringBuilder(); stats.AppendLine("Method Call Counts:"); foreach (var entry in _methodCallCounts) { stats.AppendLine($"{entry.Key}: {entry.Value}"); } return stats.ToString(); } [HttpGet] public async Task<List<string>> GetWeatherForecast3() { var tasks = new List<Task<string>>(); for (int i = 0; i < 20; i++) { if (i >= 10) { int b = i; } // 等待直到Semaphore允许进入 await globalSemaphore.WaitAsync(); int localI = i; tasks.Add(Task.Run(async Task<string> () => { try { return await SimulateRemoteRequest2(localI); } finally { // 完成任务后释放Semaphore globalSemaphore.Release(); subNum2(); } })); } // 等待所有任务完成 await Task.WhenAll(tasks); List<string> list = new List<string>(); foreach (var item in tasks) { list.Add(item.Result); } string msg = GetStatistics(); list.Add(msg); return list; } private async Task<string> SimulateRemoteRequest2(int i) { _logger.LogInformation("task " + i + " started" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); addNum2(); // Simulate a delay to represent an IO-intensive operation await Task.Delay(10000); // Simulate a 2 second delay // Optionally, make a real HTTP request to simulate a remote call // var response = await _httpClient.GetAsync("https://example.com"); // var content = await response.Content.ReadAsStringAsync(); // For simulation purposes, we return a fixed message return "task " + i + " completed"; } private static readonly object _lock2 = new object(); private void addNum2() { lock (_lock2) { num2 = num2 + 1; _logger.LogInformation("num2:" + num2); } } private void subNum2() { lock (_lock2) { num2 = num2 - 1; _logger.LogInformation("num2:" + num2); } } } }
总的来说,要全局限制一个接口的并发量,规范的方法是使用过滤器;
临时性方法是直接在控制器中定义静态信号量,然后去控制具体的接口并发量。
标签:web,Task,await,private,api,asp,var,new,logger From: https://www.cnblogs.com/Tpf386/p/18222615