public async Task LimitingThreads(TaskCreationOptions options, bool configureAwait)
{
$"Running with creation options {options} and ConfigureAwait({configureAwait})".Output();
#region Cancellation AsBefore
var runningTasks = new ConcurrentDictionary<Task, Task>();
var semaphore = new SemaphoreSlim(800);
var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(2));
var token = tokenSource.Token;
int numberOfTasks = 0;
#endregion
var scheduler = new LimitedConcurrencyLevelTaskScheduler(8);
var pumpTask = Task.Run(async () =>
{
while (!token.IsCancellationRequested)
{
await semaphore.WaitAsync(token).ConfigureAwait(false);
var runningTask = Task.Factory.StartNew(() =>
{
Interlocked.Increment(ref numberOfTasks);
return HandleMessageUnderSpecialScheduler(configureAwait, token);
}, CancellationToken.None, options, scheduler)
.Unwrap();
#region Tracking and Housekeeping AsBefore
runningTasks.TryAdd(runningTask, runningTask);
runningTask.ContinueWith(t =>
{
semaphore.Release();
Task taskToBeRemoved;
runningTasks.TryRemove(t, out taskToBeRemoved);
}, TaskContinuationOptions.ExecuteSynchronously)
.Ignore();
#endregion
}
});
await pumpTask.IgnoreCancellation().ConfigureAwait(false);
await Task.WhenAll(runningTasks.Values).IgnoreCancellation().ConfigureAwait(false);
tokenSource.Dispose();
$"Consumed {numberOfTasks} messages with concurrency {semaphore.CurrentCount} in 5 seconds. Throughput {numberOfTasks / 5} msgs/s".Output();
}