Skip to content

Instantly share code, notes, and snippets.

@devops-school
Created November 26, 2025 07:56
Show Gist options
  • Select an option

  • Save devops-school/fd0f12f77a81de2384f6bade64598e0c to your computer and use it in GitHub Desktop.

Select an option

Save devops-school/fd0f12f77a81de2384f6bade64598e0c to your computer and use it in GitHub Desktop.
DOTNET: Threading Design Example threading anti-patternsm, proper async/await & concurrency behavior
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
// Minimal API demo to show bad vs good threading practices in .NET
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Simple concurrency metrics
int currentBad = 0, maxBad = 0;
int currentGood = 0, maxGood = 0;
app.MapGet("/", () =>
"ThreadingDemo running. Use /bad, /good, /stats. Load-test /bad vs /good to see differences."
);
// ❌ BAD ENDPOINT: blocking, sync-over-async, Thread.Sleep
app.MapGet("/bad", () =>
{
var concurrent = Interlocked.Increment(ref currentBad);
UpdateMax(ref maxBad, concurrent);
var sw = Stopwatch.StartNew();
try
{
// Simulate some blocking CPU work
Thread.Sleep(20); // blocks the thread
// Simulate I/O done in a bad way: sync-over-async
for (int i = 0; i < 10; i++)
{
// BAD: This blocks the thread while waiting for an async operation
Task.Delay(100).GetAwaiter().GetResult();
}
sw.Stop();
return Results.Text(
$"BAD handled in {sw.ElapsedMilliseconds} ms; " +
$"current BAD concurrency = {concurrent}"
);
}
finally
{
Interlocked.Decrement(ref currentBad);
}
});
// ✅ GOOD ENDPOINT: proper async/await, no blocking
app.MapGet("/good", async () =>
{
var concurrent = Interlocked.Increment(ref currentGood);
UpdateMax(ref maxGood, concurrent);
var sw = Stopwatch.StartNew();
try
{
// Async-friendly "work" - yields the thread
await Task.Delay(20);
// Same simulated I/O, but correctly awaited
for (int i = 0; i < 10; i++)
{
await Task.Delay(100);
}
sw.Stop();
return Results.Text(
$"GOOD handled in {sw.ElapsedMilliseconds} ms; " +
$"current GOOD concurrency = {concurrent}"
);
}
finally
{
Interlocked.Decrement(ref currentGood);
}
});
// Expose simple stats so you can see concurrency behavior
app.MapGet("/stats", () =>
{
return Results.Json(new
{
currentBad,
maxBad,
currentGood,
maxGood
});
});
app.Run();
static void UpdateMax(ref int max, int value)
{
int initial;
do
{
initial = max;
if (value <= initial)
break;
} while (Interlocked.CompareExchange(ref max, value, initial) != initial);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment