In this article you learn how to measure and fix interactions between ThreadPool, IOCP and Kestrel in ASP.NET Core apps to reduce latency. Practical commands, code samples and measurements for .NET Core and C# training are included.
ASP.NET Core training: ThreadPool, IOCP and Kestrel Stability Under Load
Why is ThreadPool and IOCP tuning critical in .NET Core training?
In most production incidents the root cause of a "slow API" is ThreadPool ramp-up or blocking I/O; use concrete tools to detect this. First step: find the process id and monitor System.Runtime counters in real time with dotnet-counters:
ps aux | grep MyApp
# veya Windows: dotnet-trace ps
dotnet-counters monitor --process-id 12345 System.Runtime
This command gives you metrics like threadpool-thread-count, cpu-usage, time-in-gc and allocation-rate; ThreadPool growth delays can increase p95 latency. Why: .NET ThreadPool uses hill-climbing to add threads gradually, so during sudden bursts new worker threads may not be ready and requests queue up causing latency. In this section you see how to take initial measurements using tools used in .NET Core courses like dotnet-trace, dotnet-counters and PerfView..NET Core course: Real load testing and baseline measurement (wrk, k6, dotnet-trace)
Optimization without a baseline is wrong; first produce load reproducibly and then record system counters. Example 60s load test with wrk:
wrk -t8 -c200 -d60s http://localhost:5000/api/values
For more complex concurrent scenarios use a k6 script (after installing k6):
// script.js
import http from 'k6/http';
import { sleep } from 'k6';
export default function() {
http.get('http://localhost:5000/api/values');
sleep(1);
}
// çalıştırma: k6 run --vus 200 --duration 1m script.js
Collect traces with dotnet-trace during the load test:
dotnet-trace collect --process-id 12345 -o baseline.nettrace
Then analyze with PerfView or convert with dotnet-trace to inspect ThreadPool/GC/Lock events. Compare p50/p95 latency, CPU%, and threadpool-thread-count; these measurements allow you to quantify the impact of optimizations.ASP.NET Core training: MinThreads setting and example intervention
You can pre-warm production with ThreadPool.SetMinThreads, but don't use it without understanding reasons and risks. Example in Program.cs:
using System.Threading;
var builder = WebApplication.CreateBuilder(args);
// Örnek: Min worker thread sayısını artır
ThreadPool.GetMinThreads(out var worker, out var io);
ThreadPool.SetMinThreads(Math.Max(worker, 128), Math.Max(io, 128));
var app = builder.Build();
app.MapGet("/", () => "OK");
app.Run();
Why it helps: instead of hill-climbing, sufficient worker threads are available at startup, reducing queuing for I/O-bound work and lowering p95. But the risk: unnecessarily high MinThreads can increase CPU context switching. To validate, run the same wrk scenario and record dotnet-counters before and after:
dotnet-counters monitor --process-id 12345 System.Runtime > before.txt
# MinThreads uygulandıktan sonra çalıştırın
dotnet-counters monitor --process-id 12345 System.Runtime > after.txt
Compare p95 latency and threadpool-thread-count along with context-switch indicators; if CPU time or GC frequency increases, reduce MinThreads.C# training: Reduce waiting with async I/O, ValueTask and DbContext pool
Blocking I/O or Task.Run-based sync-to-async conversions consume ThreadPool; be asynchronous end-to-end. Convert EF Core queries to async and use DbContext pooling:
// Program.cs
builder.Services.AddDbContextPool(options =>
options.UseSqlServer(connectionString), poolSize: 128);
// Controller örneği
[HttpGet]
public async Task Get(CancellationToken ct) {
var items = await _db.Customers
.AsNoTracking()
.Where(c => c.IsActive)
.ToListAsync(ct);
return Ok(items);
}
// Hafif async metodlarda ValueTask kullanımı
public ValueTask FastCounterAsync() => new ValueTask(_counter);
Why: AddDbContextPool reduces DbContext creation cost; ValueTask avoids unnecessary heap allocations. Edge case: do not leak state with pooled DbContext — do not keep DbContext static or register a scoped object as singleton. For background jobs use IDbContextFactoryvar factory = app.Services.GetRequiredService>();
using var ctx = factory.CreateDbContext();
// işlemler Entity Framework training: Connection pool, Max Pool Size and DB-side monitoring
When connection pooling is misconfigured the app may see connection timeouts or high DB memory usage. Example connection string and EF Core timeout setting:
var conn = "Server=myserver;Database=MyDb;User Id=sa;Password=Secret!;Max Pool Size=200;Min Pool Size=10;";
services.AddDbContextPool(options =>
options.UseSqlServer(conn, sql => sql.CommandTimeout(60)), poolSize: 128);
To inspect DB-side activity, query active connections on SQL Server:
SELECT host_name, COUNT(*) AS conns
FROM sys.dm_exec_connections
GROUP BY host_name;
-- veya bekleyen sorguları görmek için
SELECT session_id, status, blocking_session_id, wait_type, wait_time
FROM sys.dm_exec_requests WHERE status <> 'background';
Monitoring tips: if Max Pool Size is exhausted you'll see pooled connections exhausted or long WaitTime in ADO.NET performance counters; in that case consider query optimization, appropriate CommandTimeout or DB indexing. As part of Microsoft technology training you can automate these steps by recording ADO.NET and custom metrics (e.g. connection-pool-waits) to Prometheus + Grafana.Related Course
Frequently Asked Questions
Should I use ThreadPool.SetMinThreads during ASP.NET Core training?
Use SetMinThreads only when supported by measurements. Steps: take a baseline (wrk + dotnet-counters), apply SetMinThreads, rerun the same scenario and compare p95 latency and context-switch/sec. Example commands: wrk -t8 -c200 -d60s http://localhost:5000/api; dotnet-counters monitor --process-id 12345 System.Runtime. If CPU-bound latency or GC frequency increases, reduce MinThreads.
What common mistake occurs when using AddDbContextPool in Entity Framework training?
The most common mistake is holding pooled DbContext in long-lived references (e.g. registering DbContext as a singleton or storing it in static fields). This causes state leakage. Fix: use DbContext only within short-lived scopes or use IDbContextFactory
For C# course participants, when should I use dotnet-trace vs PerfView in production?
dotnet-trace is suitable for quick, cross-platform trace collection: dotnet-trace collect --process-id 12345 -o app.nettrace. PerfView (Windows) is richer for detailed thread/GC event analysis; you can open a .nettrace captured by dotnet-trace in PerfView. Profiling steps: 1) produce load (wrk or k6), 2) collect trace with dotnet-trace, 3) analyze threadpool/GC/lock hotspots in PerfView.
How do I know the connection pool is exhausted during .NET Core training?
Look for 'timeout' or 'connection pool exhausted' errors in app logs, high connection counts in sys.dm_exec_connections on the DB side, and ADO.NET performance counters like ActiveConnections/FreeConnections. Quick check: while running, execute SELECT host_name, COUNT(*) FROM sys.dm_exec_connections GROUP BY host_name; on SQL to see how many connections are opened concurrently.
AI / LLM Discovery
Bu makale Opendart Akademi Microsoft / C# eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.



