ASP.NET Core 3.x 并发限制的实现代码(2)

public void ConfigureServices(IServiceCollection services) { services.AddStackPolicy(options => { //最大并发请求数 options.MaxConcurrentRequests = 2; //请求队列长度限制 options.RequestQueueLimit = 1; }); services.AddControllers(); }

通过上面的配置,我们便可以对我们的应用程序执行出相应的策略.下面再来看看他是怎么实现的呢

public static IServiceCollection AddStackPolicy(this IServiceCollection services, Action<QueuePolicyOptions> configure) { services.Configure(configure); services.AddSingleton<IQueuePolicy, StackPolicy>(); return services; }

可以看到这次是通过StackPolicy类做的策略.来一起来看看主要的方法

/// <summary> /// 构造方法(初始化参数) /// </summary> /// <param></param> public StackPolicy(IOptions<QueuePolicyOptions> options) { //栈分配 _buffer = new List<ResettableBooleanCompletionSource>(); //队列大小 _maxQueueCapacity = options.Value.RequestQueueLimit; //最大并发请求数 _maxConcurrentRequests = options.Value.MaxConcurrentRequests; //剩余可用空间 _freeServerSpots = options.Value.MaxConcurrentRequests; }

当我们通过中间件请求调用,_queuePolicy.TryEnterAsync()时,首先会判断我们是否还有访问请求次数,如果_freeServerSpots>0,那么则直接给我们返回true,让中间件直接去执行下一步,如果当前队列=我们设置的队列大小的话,那我们需要取消先前请求;每次取消都是先取消之前的保留后面的请求;

public ValueTask<bool> TryEnterAsync() { lock (_bufferLock) { if (_freeServerSpots > 0) { _freeServerSpots--; return _trueTask; } // 如果队列满了,取消先前的请求 if (_queueLength == _maxQueueCapacity) { _hasReachedCapacity = true; _buffer[_head].Complete(false); _queueLength--; } var tcs = _cachedResettableTCS ??= new ResettableBooleanCompletionSource(this); _cachedResettableTCS = null; if (_hasReachedCapacity || _queueLength < _buffer.Count) { _buffer[_head] = tcs; } else { _buffer.Add(tcs); } _queueLength++; // increment _head for next time _head++; if (_head == _maxQueueCapacity) { _head = 0; } return tcs.GetValueTask(); } }

当我们请求后调用_queuePolicy.OnExit();出栈,再将请求长度递减

public void OnExit() { lock (_bufferLock) { if (_queueLength == 0) { _freeServerSpots++; if (_freeServerSpots > _maxConcurrentRequests) { _freeServerSpots--; throw new InvalidOperationException("OnExit must only be called once per successful call to TryEnterAsync"); } return; } // step backwards and launch a new task if (_head == 0) { _head = _maxQueueCapacity - 1; } else { _head--; } //退出,出栈 _buffer[_head].Complete(true); _queueLength--; } }

总结

基于栈结构的特点,在实际应用中,通常只会对栈执行以下两种操作:

向栈中添加元素,此过程被称为"进栈"(入栈或压栈);

从栈中提取出指定元素,此过程被称为"出栈"(或弹栈);

队列存储结构的实现有以下两种方式:

顺序队列:在顺序表的基础上实现的队列结构;

链队列:在链表的基础上实现的队列结构;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdswdx.html