Skip to content

Instantly share code, notes, and snippets.

@binki
Forked from AArnott/ThrottleDemo.cs
Last active May 11, 2017 15:32
Show Gist options
  • Save binki/09033a726bafd0b1c862ddf24b6c264e to your computer and use it in GitHub Desktop.
Save binki/09033a726bafd0b1c862ddf24b6c264e to your computer and use it in GitHub Desktop.
Demonstrates scheduling unbounded work and applying a throttle to keep the threadpool responsive.
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
foreach (var warmup in new[] { true, false, })
{
if (warmup)
{
Console.WriteLine("Warming up…");
}
else
{
Console.WriteLine("Running…");
}
var output = new StringBuilder();
output.AppendLine("*** WITHOUT throttling ***");
MeasureWork(output, false);
output.AppendLine("*** WITH throttling ***");
MeasureWork(output, true);
if (!warmup)
{
Console.Write(output);
}
}
}
private static void MeasureWork(StringBuilder output, bool throttle)
{
TaskScheduler scheduler = throttle
? new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, Environment.ProcessorCount * 2).ConcurrentScheduler
: TaskScheduler.Default;
output.AppendLine("Race has begun.");
var sw = Stopwatch.StartNew();
var workerTasks = new Task[800];
for (int i = 0; i < workerTasks.Length; i++)
{
workerTasks[i] = Task.Factory.StartNew(Work, CancellationToken.None, TaskCreationOptions.None, scheduler);
}
Task allFinished = Task.WhenAll(workerTasks);
allFinished.ContinueWith(_ => sw.Stop());
while (!allFinished.IsCompleted)
{
Thread.Sleep(500);
output.AppendLine("Threadpool responded in: " + MeasureThreadPoolResponsiveness());
}
output.AppendLine($"FINISHED in {sw.Elapsed}");
}
static void Work()
{
SpinWait.SpinUntil(() => false, 40);
}
static TimeSpan MeasureThreadPoolResponsiveness()
{
var sw = Stopwatch.StartNew();
Task.Run(() => sw.Stop()).Wait();
return sw.Elapsed;
}
}
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
foreach (var warmup in new[] { true, false })
{
var output = new StringBuilder();
if (warmup)
{
Console.WriteLine("Warming up…");
}
else
{
Console.WriteLine("Running…");
}
output.AppendLine("*** WITHOUT throttling ***");
MeasureWork(output, false);
output.AppendLine("*** WITH throttling ***");
MeasureWork(output, true);
if (!warmup)
{
Console.Write(output);
}
}
}
private static void MeasureWork(StringBuilder output, bool throttled)
{
SemaphoreSlim semaphore = throttled ? new SemaphoreSlim(Environment.ProcessorCount * 2) : null;
output.AppendLine("Race has begun.");
var sw = Stopwatch.StartNew();
var workerTasks = new Task[800];
for (int i = 0; i < workerTasks.Length; i++)
{
workerTasks[i] = Task.Run(async delegate
{
if (semaphore != null)
{
await semaphore.WaitAsync();
}
await WorkAsync();
semaphore?.Release();
});
}
Task allFinished = Task.WhenAll(workerTasks);
allFinished.ContinueWith(_ => sw.Stop());
while (!allFinished.IsCompleted)
{
Thread.Sleep(500);
output.AppendLine("Threadpool responded in: " + MeasureThreadPoolResponsiveness());
}
output.AppendLine($"FINISHED in {sw.Elapsed}");
}
static async Task WorkAsync()
{
SpinWait.SpinUntil(() => false, 20);
await Task.Yield();
SpinWait.SpinUntil(() => false, 20);
}
static TimeSpan MeasureThreadPoolResponsiveness()
{
var sw = Stopwatch.StartNew();
Task.Run(() => sw.Stop()).Wait();
return sw.Elapsed;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment