Improve performance for QueuePolicy in ConcurrencyLimiter (#13947)

This commit is contained in:
Kahbazi 2019-11-02 00:58:02 +03:30 committed by Stephen Halter
parent ab5b5a4ab5
commit 61179f3da2
2 changed files with 30 additions and 17 deletions

View File

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

View File

@ -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