Improve performance for QueuePolicy in ConcurrencyLimiter (#13947)
This commit is contained in:
parent
ab5b5a4ab5
commit
61179f3da2
|
|
@ -10,31 +10,35 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
|||
{
|
||||
internal class QueuePolicy : IQueuePolicy, IDisposable
|
||||
{
|
||||
private readonly int _maxConcurrentRequests;
|
||||
private readonly int _requestQueueLimit;
|
||||
private readonly int _maxTotalRequest;
|
||||
private readonly SemaphoreSlim _serverSemaphore;
|
||||
|
||||
private object _totalRequestsLock = new object();
|
||||
|
||||
public int TotalRequests { get; private set; }
|
||||
|
||||
public QueuePolicy(IOptions<QueuePolicyOptions> options)
|
||||
{
|
||||
_maxConcurrentRequests = options.Value.MaxConcurrentRequests;
|
||||
if (_maxConcurrentRequests <= 0)
|
||||
var queuePolicyOptions = options.Value;
|
||||
|
||||
var maxConcurrentRequests = queuePolicyOptions.MaxConcurrentRequests;
|
||||
if (maxConcurrentRequests <= 0)
|
||||
{
|
||||
throw new ArgumentException(nameof(_maxConcurrentRequests), "MaxConcurrentRequests must be a positive integer.");
|
||||
throw new ArgumentException(nameof(maxConcurrentRequests), "MaxConcurrentRequests must be a positive integer.");
|
||||
}
|
||||
|
||||
_requestQueueLimit = options.Value.RequestQueueLimit;
|
||||
if (_requestQueueLimit < 0)
|
||||
var requestQueueLimit = queuePolicyOptions.RequestQueueLimit;
|
||||
if (requestQueueLimit < 0)
|
||||
{
|
||||
throw new ArgumentException(nameof(_requestQueueLimit), "The RequestQueueLimit cannot be a negative number.");
|
||||
throw new ArgumentException(nameof(requestQueueLimit), "The RequestQueueLimit cannot be a negative number.");
|
||||
}
|
||||
|
||||
_serverSemaphore = new SemaphoreSlim(_maxConcurrentRequests);
|
||||
_serverSemaphore = new SemaphoreSlim(maxConcurrentRequests);
|
||||
|
||||
_maxTotalRequest = maxConcurrentRequests + requestQueueLimit;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> TryEnterAsync()
|
||||
public ValueTask<bool> TryEnterAsync()
|
||||
{
|
||||
// a return value of 'false' indicates that the request is rejected
|
||||
// a return value of 'true' indicates that the request may proceed
|
||||
|
|
@ -42,17 +46,21 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
|||
|
||||
lock (_totalRequestsLock)
|
||||
{
|
||||
if (TotalRequests >= _requestQueueLimit + _maxConcurrentRequests)
|
||||
if (TotalRequests >= _maxTotalRequest)
|
||||
{
|
||||
return false;
|
||||
return new ValueTask<bool>(false);
|
||||
}
|
||||
|
||||
TotalRequests++;
|
||||
}
|
||||
|
||||
await _serverSemaphore.WaitAsync();
|
||||
Task task = _serverSemaphore.WaitAsync();
|
||||
if (task.IsCompletedSuccessfully)
|
||||
{
|
||||
return new ValueTask<bool>(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
return SemaphoreAwaited(task);
|
||||
}
|
||||
|
||||
public void OnExit()
|
||||
|
|
@ -69,5 +77,12 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
|||
{
|
||||
_serverSemaphore.Dispose();
|
||||
}
|
||||
|
||||
private async ValueTask<bool> SemaphoreAwaited(Task task)
|
||||
{
|
||||
await task;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
|||
|
||||
private readonly object _bufferLock = new Object();
|
||||
|
||||
private readonly static ValueTask<bool> _trueTask = new ValueTask<bool>(true);
|
||||
|
||||
private int _freeServerSpots;
|
||||
|
||||
public StackPolicy(IOptions<QueuePolicyOptions> options)
|
||||
|
|
@ -40,7 +38,7 @@ namespace Microsoft.AspNetCore.ConcurrencyLimiter
|
|||
if (_freeServerSpots > 0)
|
||||
{
|
||||
_freeServerSpots--;
|
||||
return _trueTask;
|
||||
return new ValueTask<bool>(true);
|
||||
}
|
||||
|
||||
// if queue is full, cancel oldest request
|
||||
|
|
|
|||
Loading…
Reference in New Issue