Task.Delay
è implementato con un numero interno System.Threading.Timer
. Quella classe di timer è un wrapper in cima a un singolo timer nativo. Per sincronizzare l'accesso a quel singolo timer nativo c'è un livello di blocco AppDomain
sulla creazione di nuovi timer (e la modifica di quelli esistenti). Si può vedere che nel reference source:
internal bool Change(uint dueTime, uint period)
{
// ...
lock (TimerQueue.Instance)
{
// ...
}
// ...
}
Nella maggior parte dei casi va bene, ma quando si crea una notevole quantità di questi timer al secondo è possibile ottenere un grave contenzioso su quel blocco. L'unico modo per sapere in realtà è il profilo in un ambiente reale.
io, personalmente, hanno raggiunto quel punto con la creazione di auto-cancellazione di troppi CancellationTokenSource
utilizzando i timer (si può vedere come ho evitato che sul mio blog: Surprising Contention In System.Threading.Timer
).
C'è anche questo post di Stephen Toub su Coalescing CancellationToken
s from Timeouts che cita:
"Certo, ci sono sempre gli scenari la spinta i confini delle prestazioni, e di recente abbiamo visto alcuni casi di alto throughput, la gente stava creando uno di questi CancellationToken
per ciascuna delle migliaia e migliaia di chiamate asincrone effettuate al secondo. Si tratta di un sacco di istanze Timer
e CancellationTokenSource
".
AFAIK, tutte le attività utilizzano i thread allocati da un ThreadPool. Se si desidera garantire alcuni requisiti prestazionali personalizzati, è sempre possibile creare una TaskFactory personalizzata adatta alle proprie esigenze. – d3dave
@ d3dave no non è affatto vero. Task.Delay utilizza i timer non i thread. TaskCompletionSource è un altro esempio di Attività senza thread. –