Task.Delay is implemented with internal System.Threading.Timer . This timer class is a wrapper on top of one built-in timer. To synchronize access to this single built-in timer, lock the AppDomain level to create new timers (and modify existing ones). You can see this in the reference source :
internal bool Change(uint dueTime, uint period) {
In most cases, this is normal, but when you create a significant amount of these timers per second, you can get serious competition in this lock. The only way to learn how to profile your application in a real environment .
I personally reached this point by creating too many self-curing CancellationTokenSource using timers (you can see how I avoided this on my blog: An amazing conflict in System.Threading.Timer ).
There's also this Steven Tuub post on Coalescing CancellationToken from Timeouts , which mentions:
βOf course, there are always scenarios that push the boundaries of performance, and recently seen some high-performance cases where people created one such CancellationToken for each of the thousands and thousands of asynchronous calls per second . These are many instances of Timer and CancellationTokenSource .
source share