await Task.Delay takes longer than expected
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
await Task.Delay(milliseconds) guarantees a minimum delay, not an exact one. The actual wait can be longer due to the system timer resolution (typically 15.6ms on Windows), thread pool saturation, synchronization context overhead, and GC pauses. A Task.Delay(100) might actually wait 109ms or 115ms. If you need precise timing, Task.Delay is the wrong tool. Use a high-resolution timer or Stopwatch-based loop instead.
Windows Timer Resolution
The Windows system timer fires at a default interval of 15.625ms (64 Hz). Task.Delay uses this timer internally:
Task.Delay(1) does not wait 1ms. It waits until the next timer tick, which is up to 15.6ms away. Any delay under 16ms effectively becomes a 16ms delay.
The actual delay is rounded up to the next multiple of 15.6ms.
Thread Pool Starvation
When all thread pool threads are busy, the continuation after await Task.Delay must wait for a free thread:
The delay timer fires on time, but the continuation cannot run until a thread pool thread is available.
SynchronizationContext Overhead
In UI apps (WPF, WinForms), await captures the synchronization context and resumes on the UI thread:
If the UI thread is busy (rendering, handling events), the continuation waits in the dispatcher queue.
GC Pauses
Garbage collection can pause all managed threads:
Server GC mode and concurrent GC reduce pause times but cannot eliminate them entirely.
Measuring Accurately
Improving Timer Resolution (Windows)
timeBeginPeriod(1) increases power consumption system-wide. Only use it when precise timing is critical, and always restore with timeEndPeriod.
Alternatives for Precise Timing
PeriodicTimer corrects for drift over time. If one tick is late, the next tick fires sooner.
Task.Delay(0) Behavior
Common Pitfalls
- Expecting exact timing:
Task.Delayis a minimum-delay timer, not a precise one. It is never shorter than requested but can be significantly longer. - Using Task.Delay for game loops: Game loops need consistent frame timing. Use
Stopwatchto measure elapsed time and adjust, or use a dedicated game timer. - Thread.Sleep vs Task.Delay:
Thread.Sleepblocks the thread (cannot be cancelled, wastes a thread).Task.Delayreleases the thread. Always preferTask.Delayin async code. - Ignoring ConfigureAwait: In UI apps,
await Task.Delay(100)resumes on the UI thread. Use.ConfigureAwait(false)when you do not need the UI thread to reduce latency. - Cumulative drift: Running
await Task.Delay(100)in a loop accumulates error. After 100 iterations, you might be 500ms late. UsePeriodicTimeror a Stopwatch-based correction loop.
Summary
Task.Delayguarantees a minimum delay, not an exact one- Windows timer resolution (15.6ms default) is the primary cause of extra delay
- Thread pool starvation, synchronization context, and GC pauses add further overhead
- Use
ConfigureAwait(false)to avoid UI thread marshaling overhead - Use
PeriodicTimer(.NET 6+) for drift-correcting repeated intervals - For sub-millisecond precision, use
Stopwatch-based spin loops (at the cost of CPU usage)
Related reading
- AWS Athena too slow for an api?
- AWS EBS Volume in-use - optimizing
- AWS Load Balancer 502
- AWS RDS Provisioned IOPS really worth it?
- awaitable Task based queue
- await/async Why the 2 pieces of code doesn't run the same?
- Awaiting multiple Tasks with different results
- AWS sdk for .net queryAsync method using global secondary index fails

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.