Cuándo usar Task.Delay, cuándo usar Thread.Sleep?

¿Hay una (s) regla (s) válida (s) para cuándo usar Tarea.Delay versus Thread.Sleep ?

  • Específicamente, ¿existe un valor mínimo para que uno sea efectivo / eficiente sobre el otro?
  • Por último, dado que Task.Delay provoca el cambio de contexto en una máquina de estado async / await, ¿hay una sobrecarga de usarlo?

Use Thread.Sleep cuando quiera bloquear el hilo actual.

Use Task.Delay cuando desee un retraso lógico sin bloquear el hilo actual.

La eficiencia no debe ser una preocupación primordial con estos métodos. Su uso principal en el mundo real es como temporizadores de rebash para operaciones de E / S, que son del orden de segundos en lugar de milisegundos.

La mayor diferencia entre Task.Delay y Thread.Sleep es que Task.Delay está destinado a ejecutarse de forma asíncrona. No tiene sentido utilizar Task.Delay en el código síncrono. Es una MUY mala idea usar Thread.Sleep en un código asíncrono.

Normalmente llamará a Task.Delay() con la palabra clave Task.Delay() :

 await Task.Delay(5000); 

o, si desea ejecutar algún código antes de la demora:

 var sw = new Stopwatch(); sw.Start(); Task wait = Task.Delay(5000); Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds); await wait; 

¿Adivina qué imprimirá esto? Corriendo por 0.0070048 segundos. Si movemos la await wait encima de Console.WriteLine , se imprimirá en ejecución durante 5.0020168 segundos.

Veamos la diferencia con Thread.Sleep :

 class Program { static void Main(string[] args) { Task wait = asyncTask(); syncCode(); wait.Wait(); Console.ReadLine(); } static async Task asyncTask() { var sw = new Stopwatch(); sw.Start(); Console.WriteLine("async: Starting"); Task wait = Task.Delay(5000); Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds); await wait; Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds); Console.WriteLine("async: Done"); } static void syncCode() { var sw = new Stopwatch(); sw.Start(); Console.WriteLine("sync: Starting"); Thread.Sleep(5000); Console.WriteLine("sync: Running for {0} seconds", sw.Elapsed.TotalSeconds); Console.WriteLine("sync: Done"); } } 

Intenta predecir lo que esto imprimirá …

asincrónico: comenzando
asincrónica: se ejecuta durante 0.0070048 segundos
sincronización: comenzando
asincrónica: se ejecuta durante 5.0119008 segundos
asincrónico: Hecho
sincronización: corriendo por 5.0020168 segundos
sincronización: Hecho

Además, es interesante observar que Thread.Sleep es mucho más preciso, la precisión de ms no es realmente un problema, mientras que Task.Delay puede tardar de 15 a 30 ms en mínimo. La sobrecarga de ambas funciones es mínima en comparación con la precisión ms que tienen (use Stopwatch si necesita algo más preciso). Thread.Sleep todavía ata su Thread, Task.Delay para hacer otro trabajo mientras espera.

si se elimina el hilo actual y utiliza Thread.Sleep y se está ejecutando, es posible que obtenga una ThreadAbortException . Con Task.Delay siempre puede proporcionar un token de cancelación y matarlo con gracia. Esa es una razón por la que elegiría Task.Delay . ver http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx

También estoy de acuerdo en que la eficiencia no es primordial en este caso.

Quiero agregar algo En realidad, Task.Delay es un mecanismo de espera basado en temporizador. Si mira la fuente , encontrará una referencia a una clase Timer que es responsable de la demora. Por otro lado, Thread.Sleep realmente hace que el hilo actual se quede dormido, de esa forma solo estás bloqueando y desperdiciando un hilo. En el modelo de progtwigción asíncrona, siempre debe usar Task.Delay() si desea que ocurra algo (continuación) después de algún retraso.

Estas son operaciones funcionalmente equivalentes, simplemente crean una pausa, pero Task.Delay es a la espera.

Encontré una forma de hackear Thread.Sleep haciendo que el progtwig se active periódicamente y realice eventos si realmente debe usarlo. Vea abajo:

 // Pay attention every 1/10 sec to maintain some UI responsiveness while (val > 0) { Thread.Sleep(100); val = val - 100; Application.DoEvents(); if (val == x) { // You could do some conditional stuff here at specific times } } 

Sustituya val con el retraso deseado en milisegundos. Cuanto más Thread.Sleep el valor ms de Thread.Sleep más receptivo parecerá el progtwig. 100ms me parece aceptable. 50 ms es lo mejor