Find the Best Cosmetic Hospitals

Explore trusted cosmetic hospitals and make a confident choice for your transformation.

โ€œInvest in yourself โ€” your confidence is always worth it.โ€

Explore Cosmetic Hospitals

Start your journey today โ€” compare options in one place.

DOTNET: Threading Design Example threading anti-patternsm, proper async/await & concurrency behavior


We can do this with one self-contained minimal API that has:

  • A โ€œbadโ€ endpoint showing threading anti-patterns (blocking, .Result, Thread.Sleep)
  • A โ€œgoodโ€ endpoint using proper async/await
  • A /stats endpoint to see concurrency behavior
  • Then weโ€™ll use dotnet-counters + simple load to see the impact.

1๏ธโƒฃ Create the project

dotnet new web -n ThreadingDemo
cd ThreadingDemo
Code language: JavaScript (javascript)

Replace all contents of Program.cs with this:

This single file gives you:

  • /bad โ†’ blocked threads / ThreadPool pressure
  • /good โ†’ healthy async behavior
  • /stats โ†’ concurrency snapshot

2๏ธโƒฃ Run the app

From the ThreadingDemo folder:

dotnet run

It will listen on:

  • http://localhost:5000 (default)

Test quickly:

curl http://localhost:5000/bad
curl http://localhost:5000/good
curl http://localhost:5000/stats
Code language: JavaScript (javascript)

3๏ธโƒฃ Experience the problem: BAD threading under load

The /bad endpoint:

  • Uses Thread.Sleep() โ†’ blocks the thread
  • Uses Task.Delay(100).Result โ†’ sync-over-async, blocks the thread
  • Under concurrent load, the ThreadPool threads get stuck, new requests wait โ‡’ latency goes up, throughput drops.

๐Ÿงช Simulate load on /bad

Option A โ€“ PowerShell (parallel-ish)

# Fire 50 requests, roughly in parallel
1..50 | ForEach-Object {
    Start-Job { curl "http://localhost:5000/bad" }
}
Code language: PHP (php)

Or more aggressively:

1..200 | ForEach-Object {
    Start-Job { curl "http://localhost:5000/bad" }
}
Code language: JavaScript (javascript)

Then check:

curl "http://localhost:5000/stats"
Code language: JavaScript (javascript)

Youโ€™ll see:

  • maxBad grow
  • Responses from /bad will be slow (hundreds or thousands of ms)

4๏ธโƒฃ Compare with GOOD endpoint under same load

Do the same with /good:

1..200 | ForEach-Object {
    Start-Job { curl "http://localhost:5000/good" }
}
curl "http://localhost:5000/stats"
Code language: JavaScript (javascript)

You should observe:

  • GOOD handled in ... ms is more stable
  • maxGood may be higher (more concurrency successfully handled)
  • Latency is smoother because threads are not blocked โ€” theyโ€™re freed while awaiting.

5๏ธโƒฃ Debug / Observe Threading Issues with Tools

Now letโ€™s add tools on top, so you can show this in training.

๐Ÿ”น Step 1: Find the process ID

In a new terminal:

dotnet-counters ps

Look for ThreadingDemo / dotnet with the project path.

Note the PID (e.g., 12345).


๐Ÿ”น Step 2: Monitor runtime with dotnet-counters

Run:

dotnet-counters monitor --process-id <PID> System.Runtime Microsoft.AspNetCore.Hosting
Code language: CSS (css)

Watch these metrics while hitting /bad vs /good:

Key ones:

  • ThreadPool Thread Count
  • ThreadPool Queue Length
  • CPU Usage
  • Requests / sec (from hosting)
  • gc-heap-size

What you should see

When hammering /bad:

  • ThreadPool Thread Count goes up
  • ThreadPool Queue Length might stay elevated
  • CPU can be high due to lots of blocking and context switching
  • Requests/sec typically lower than expected

When hammering /good:

  • ThreadPool threads are reused efficiently
  • Queue Length often stays low
  • CPU usage is better for same number of requests
  • Requests/sec improves, latency is lower

๐Ÿ”น Step 3: Visual Studio Diagnostic Tools (optional)

If you run from Visual Studio:

  1. Start the app with Debug โ†’ Start Debugging.
  2. Open Debug โ†’ Windows โ†’ Parallel Stacks / Parallel Tasks.
  3. Watch the number of running threads and tasks as you hammer /bad and /good.

Youโ€™ll see:

  • For /bad: more stuck threads, longer lifetimes
  • For /good: tasks start/complete quickly, threads not held hostage

6๏ธโƒฃ How to explain this behavior conceptually

In /bad:

  • Thread.Sleep โ†’ the worker thread is doing nothing but cannot process other requests.
  • Task.Delay(...).Result โ†’ the operation is asynchronous internally, but you force it to be synchronous, so:
    • The thread blocks until delay finishes
    • Under load: too many blocked threads โ†’ ThreadPool grows โ†’ context switching overhead โ†’ queue length and latency grow.

In /good:

  • await Task.Delay(...) โ†’ the thread returns to the pool while waiting
  • When the delay completes, the continuation resumes (on a thread pool worker)
  • The same set of threads can handle many more in-flight requests.

So itโ€™s mostly a programming practice issue, not a โ€œ.NET design flawโ€:

  • โŒ Bad code: blocking, sync-over-async, Thread.Sleep on server
  • โœ… Good code: async all the way, no .Result, no .Wait()

7๏ธโƒฃ Quick summary for your training slide

You can summarize this demo as:

  • /bad: Blocking calls (Thread.Sleep, .Result) โ†’ ThreadPool starvation โ†’ high latency, low throughput
  • /good: Proper async/await โ†’ threads freed โ†’ better scalability and responsiveness
  • Tools: dotnet-counters + /stats endpoint give direct visibility into concurrency & runtime behavior.

Find Trusted Cardiac Hospitals

Compare heart hospitals by city and services โ€” all in one place.

Explore Hospitals
Iโ€™m a DevOps/SRE/DevSecOps/Cloud Expert passionate about sharing knowledge and experiences. I have worked at <a href="https://www.cotocus.com/">Cotocus</a>. I share tech blog at <a href="https://www.devopsschool.com/">DevOps School</a>, travel stories at <a href="https://www.holidaylandmark.com/">Holiday Landmark</a>, stock market tips at <a href="https://www.stocksmantra.in/">Stocks Mantra</a>, health and fitness guidance at <a href="https://www.mymedicplus.com/">My Medic Plus</a>, product reviews at <a href="https://www.truereviewnow.com/">TrueReviewNow</a> , and SEO strategies at <a href="https://www.wizbrand.com/">Wizbrand.</a> Do you want to learn <a href="https://www.quantumuting.com/">Quantum Computing</a>? <strong>Please find my social handles as below;</strong> <a href="https://www.rajeshkumar.xyz/">Rajesh Kumar Personal Website</a> <a href="https://www.youtube.com/TheDevOpsSchool">Rajesh Kumar at YOUTUBE</a> <a href="https://www.instagram.com/rajeshkumarin">Rajesh Kumar at INSTAGRAM</a> <a href="https://x.com/RajeshKumarIn">Rajesh Kumar at X</a> <a href="https://www.facebook.com/RajeshKumarLog">Rajesh Kumar at FACEBOOK</a> <a href="https://www.linkedin.com/in/rajeshkumarin/">Rajesh Kumar at LINKEDIN</a> <a href="https://www.wizbrand.com/rajeshkumar">Rajesh Kumar at WIZBRAND</a> <a href="https://www.rajeshkumar.xyz/dailylogs">Rajesh Kumar DailyLogs</a>

Related Posts

Top 10 LLM Evaluation Harnesses: Features, Pros, Cons & Comparison

Introduction LLM Evaluation Harnesses are tools, frameworks, and platforms that help teams test large language models, prompts, RAG pipelines, chatbots, copilots, and AI agents before they are…

Read More

Top 10 Model Benchmarking Suites: Features, Pros, Cons & Comparison

Introduction Model Benchmarking Suites help AI teams test, compare, and validate machine learning models, large language models, multimodal models, and AI agents before they are deployed in…

Read More

Top 10 Model Compression Toolkits: Features, Pros, Cons & Comparison

Introduction Model compression toolkits help AI teams reduce the size, memory usage, latency, and serving cost of machine learning models while keeping useful performance as high as…

Read More

Top 10 Model Quantization Tooling: Features, Pros, Cons & Comparison

Introduction Model quantization tooling helps AI teams make models smaller, faster, and cheaper to run by reducing numerical precision. Instead of running every model weight or activation…

Read More

Top 10 Model Distillation Toolkits: Features, Pros, Cons & Comparison

Introduction Model distillation toolkits help AI teams transfer knowledge from a larger, more capable model into a smaller, faster, and cheaper model. In simple terms, the larger…

Read More

Top 10 RLHF / RLAIF Training Platforms: Features, Pros, Cons & Comparison

Introduction RLHF and RLAIF training platforms help AI teams improve model behavior using structured feedback. RLHF, or reinforcement learning from human feedback, uses human preference signals, ratings,…

Read More
Subscribe
Notify of
guest
3 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Jason Mitchell
Jason Mitchell
5 months ago

Awesome writeโ€‘up โ€” this article does a great job showing how easy it is for .NET developers to accidentally fall into threading antiโ€‘patterns if they donโ€™t understand the difference between blocking and asynchronous design. The contrast between the โ€œbadโ€ endpoint (blocking calls like Thread.Sleep() or .Result) and the โ€œgoodโ€ endpoint using proper async/await really illustrates how blocking threads under load can lead to ThreadPool starvation, high latency and poor scalability. I also like how the accompanying /stats endpoint + dotnetโ€‘counters demo makes the consequences of bad design visible โ€” thatโ€™s a powerful lesson for anyone building scalable HTTP services. For modern web APIs or highโ€‘traffic services, adopting async patterns over synchronous/blocking calls is not just best practice โ€” itโ€™s essential for responsiveness and throughput. ๐Ÿ‘

Skylar Bennett
Skylar Bennett
5 months ago

This article gives a very clear and practical illustration of the risks of โ€œblockingโ€‘threadโ€ antiโ€‘patterns and why embracing proper async/await concurrency is essential in .NET applications. The contrast between the /bad endpoint (with blocking calls like Thread.Sleep() or .Result) and the /good endpoint (using await Task.Delay(...)) shows in a concrete, measurable way how blocking threads under load kills throughput and raises latency, while async code keeps threads free, improves scalability and responsiveness. Using tools like dotnetโ€‘counters to monitor threadโ€‘pool usage and requestโ€‘perโ€‘second under load adds realโ€‘world observability โ€” a great teaching aid for developers or when training teams. Overall, itโ€™s a highly useful resource for anyone designing concurrent .NET services, particularly in web/server contexts.

Skylar Bennett
Skylar Bennett
5 months ago

this article gives a very clear and practical illustration of the risks of โ€œblockingโ€‘threadโ€ antiโ€‘patterns and why embracing proper async/await concurrency is essential in .NET applications. The contrast between the /bad endpoint (with blocking calls like Thread.Sleep() or .Result) and the /good endpoint (using await Task.Delay(...)) shows in a concrete, measurable way how blocking threads under load kills throughput and raises latency, while async code keeps threads free, improves scalability and responsiveness. Using tools like dotnet-counters to monitor threadโ€‘pool usage and requestโ€‘perโ€‘second under load adds realโ€‘world observability โ€” a great teaching aid for developers or when training teams. Overall, itโ€™s a highly useful resource for anyone designing concurrent .NET services, particularly in web/server contexts.

3
0
Would love your thoughts, please comment.x
()
x