Alternativas a Thread.Sleep ()

Cada N minutos que queremos ejecutar a través de una lista de tareas. Así que creamos un ejecutor de tareas con un

do { DoWork(); }while(!stopRequested) 

Ahora queremos tener una pausa entre los ciclos de trabajo. Todo el mundo parece pensar que Thread.Sleep () es el demonio. He visto mencionar el uso de Monitor / Evento, pero no tenemos a alguien más diciéndonos que hagamos el trabajo. Solo queremos hacer cosas cada N minutos como un reloj.

Entonces, ¿hay alguna alternativa o he encontrado un uso válido de Thread.Sleep?

Alguien en otra publicación mencionó WaitHandle.WaitOne () como alternativa, pero aparentemente no se puede llamar a eso desde un método no estático. O al menos no puedo porque obtengo un error de comstackción de ..

Se requiere una referencia de objeto para el campo, método o propiedad no estático ‘System.Threading.WaitHandle.WaitOne (System.TimeSpan)’

Tienes que llamar a WaitOne en un WaitHandle , sin dudas. Es un método de instancia. De lo contrario, ¿cómo sabría qué esperar?

Definitivamente es mejor tener algo que pueda reactjsr en lugar de dormir, para que pueda notar la cancelación sin esperar minutos sin motivo. Otra alternativa a WaitHandle es usar Monitor.Wait / Pulse .

Sin embargo, si usa .NET 4, analizaré lo que ofrece la Biblioteca paralela de tareas … está en un nivel ligeramente más alto que las otras opciones, y generalmente es una biblioteca bien pensada.

Para las tareas de trabajo regulares, es posible que desee ver el uso de un Timer (ya sea System.Threading.Timer o System.Timers.Timer ) o posiblemente incluso Quartz.NET .

Según tengo entendido, Thread.Sleep () es malo porque fuerza a los recursos del subproceso a salir del caché, por lo que deben volver a cargarse después. No es gran cosa, pero podría agravar los problemas de rendimiento en situaciones de mucha carga. Y luego está el hecho de que el tiempo no es preciso, y que efectivamente no puede esperar por duraciones de menos de 10 ms …

Yo uso este fragmento:

 new System.Threading.ManualResetEvent(false).WaitOne(1000); 

Fácil como un pastel y todo encaja en una línea. Crea un nuevo controlador de eventos que nunca se establecerá, y luego espera el período de tiempo de espera completo, que usted especifica como el argumento para WaitOne() .

Aunque, para este escenario específico, un temporizador probablemente sería un enfoque más apropiado:

 var workTimer = new System.Threading.Timer( (x) => DoWork(), null, 1000, // initial wait period 300000); // subsequent wait period 

Luego, en lugar de establecer una variable de cancelación, detendría el temporizador con workTimer.Stop() .


Editar :

Como las personas aún lo encuentran útil, debo agregar que .NET 4.5 introduce el método Task.Delay , que es aún más conciso y también admite asincrónico:

 Task.Delay(2000).Wait(); // Wait 2 seconds with blocking await Task.Delay(2000); // Wait 2 seconds without blocking 

Thread.Sleep no es el demonio, podrías usarlo para un escenario como este. No es muy confiable por cortas duraciones.

Usar un WaitHandle es una buena opción, pero necesita una instancia específica de un identificador de espera. No hará esto solo, sin embargo.

Dicho esto, la mayoría de las veces, operaciones como esta son más adecuadas para usar un temporizador. ¿Hay alguna razón por la que intente procesar esto en un bucle en lugar de simplemente usar un temporizador para comenzar el elemento de trabajo?

Las tres opciones que puedo pensar en la parte superior de mi cabeza son:

  • System.Threading.Timer ( más … )
  • Monitor.Wait ( Más … )
  • System.Timers.Timer ( Más … )

pero estoy seguro de que muchos mencionarán: Thread.Sleep() no es tan malo.

Puede usar un ManualResetEvent que establezca cuando sea el momento de detenerse, y luego hacer un WaitOne en él.

Yo usaría un temporizador de espera que señala un AutoResetEvent. Su hilo debe esperar a este objeto WaitHandle. Aquí hay una pequeña aplicación de consola que muestra este enfoque:

 class Program { const int TimerPeriod = 5; static System.Threading.Timer timer; static AutoResetEvent ev; static void Main(string[] args) { ThreadStart start = new ThreadStart(SomeThreadMethod); Thread thr = new Thread(start); thr.Name = "background"; thr.IsBackground = true; ev = new AutoResetEvent(false); timer = new System.Threading.Timer( Timer_TimerCallback, ev, TimeSpan.FromSeconds(TimerPeriod), TimeSpan.Zero); thr.Start(); Console.WriteLine(string.Format("Timer started at {0}", DateTime.Now)); Console.ReadLine(); } static void Timer_TimerCallback(object state) { AutoResetEvent ev = state as AutoResetEvent; Console.WriteLine(string.Format ("Timer's callback method is executed at {0}, Thread: ", new object[] { DateTime.Now, Thread.CurrentThread.Name})); ev.Set(); } static void SomeThreadMethod() { WaitHandle.WaitAll(new WaitHandle[] { ev }); Console.WriteLine(string.Format("Thread is running at {0}", DateTime.Now)); } }