asp.net web api 接口控制并发研究(临时性方法)

有一个业务场景,接口的业务逻辑非常复杂,对数据库的压力比较大,希望限制下接口的并发数量,研究了下:

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);
            }

        }



    }
}

 

总的来说,要全局限制一个接口的并发量,规范的方法是使用过滤器;

临时性方法是直接在控制器中定义静态信号量,然后去控制具体的接口并发量。

 

posted on 2024-05-30 16:20  荆棘人  阅读(37)  评论(0编辑  收藏  举报

导航