2011-12-08 33 views
6

Tengo un dll consumido por un servicio. Su trabajo básico es ejecutar cada X minutos y realizar algunas comprobaciones del sistema. En mi dll tengo una clase de nivel superior que declara System.threading.timer y Timercallback. El constructor de la clase inicializa timerCallback con mi función de hilo. En mi controlador "Onstart", inicializo el temporizador con el timercalback y configuré la próxima vez para disparar y el intervalo de tiempo. En mi caso es cada 10 minutos. Por lo general, en estos controles de 10 minutos no hay nada que hacer, pero el servicio se ve obligado a hacer algo al menos una vez al día a una hora determinada.C# .NET 2 Threading.Timer - time drifting

Mi problema: Estoy comprobando que durante las pruebas, el tiempo que se lleva a cabo la verificación diaria se está alejando lentamente del tiempo de inicio deseado de 8,30. p.ej. durante aproximadamente 20 días impares, mi tiempo ha pasado de 08.30 a 08.31.35. Se desplaza entre 4 y 6 segundos todos los días.

Mi pregunta: ¿Alguien sabe por qué el tiempo se está desviando así y cómo puedo hacer que se mantenga en el tiempo asignado?

gracias

+0

No estoy seguro en base a la pregunta, pero parece estar leyendo que usted programa un temporizador para hacer algo en 10 minutos, cuya primera acción es programar otra tarea en 10 minutos. No programar una tarea cada 10 minutos. ¿Podría publicar el código del temporizador? – Sign

+0

Solo configuro el temporizador una vez, cuando el servicio se inicia por primera vez y luego lo configuro para que se dispare cada 10 minutos. Es como si cada "tic" de 10 minutos a partir de ese momento se desvanecie gradualmente más adelante. ¡Es difícil agregar código porque no puedo poner retornos de carro en este cuadro de texto! – Keith

+0

@Keith - No se supone que tenga una discusión completa por comentarios. Si tienes código para publicar, actualiza tu pregunta. –

Respuesta

6

El tiempo de "deriva" debido a que el temporizador no es simplemente que preciso. Si necesita ejecutar el código lo más cerca posible a un cierto intervalo, se puede hacer algo como esto:

public void MyTimerCallback(object something) { 
    var now = DateTime.UtcNow; 
    var shouldProbablyHaveRun = new DateTime(
     now.Year, now.Month, now.Day, 
     now.Hour, now.Minute - (now.Minute % 10), 0); 
    var nextRun = shouldProbablyHaveRun.AddMinutes(10.0); 

    // Do stuff here! 

    var diff = nextRun - DateTime.UtcNow; 
    timer.Change(diff, new TimeSpan(-1)); 
} 

... suponiendo que está utilizando una instancia System.Threading.Timer. Modifique el ejemplo si está utilizando cualquier otro tipo de temporizador (¡hay varios!).

+0

Esto se ve bien gracias. Estoy usando un system.threading.timer, ¿sería mejor cambiar a Timers. Entonces, Timer? – Keith

+1

Actualicé mi respuesta al uso de 'System.Threading.Timer'. Diferentes temporizadores tienen beneficios para diferentes situaciones. Si tu cronómetro ha funcionado para ti hasta ahora, no hay razón para cambiar. Acepte mi respuesta como respuesta si funciona para usted. :) –

+0

@Keith: 'System.Timers.Timer' en realidad usa' System.Threading.Timer' detrás de las escenas. Entonces realmente no importa, pero el primero es un poco más conveniente de usar. –

0

¿Por qué no comprobar cada minuto si la acción debe realizarse?

es decir:

if (DateTime.Now.Minute % 10) == 0 
+0

Si el temporizador se inicia a las 6:01, cada 10 minutos cuando revisa, 'DateTime.Now.Minute% 10' no será' 0' :) –

0

se necesita una cantidad finita de tiempo para hacer las operaciones que está haciendo en su controlador de métodos temporizador, así que tiene sentido que no va a pasar cada 10 minutos para la segunda, especialmente si está programando el próximo despertar después de hacer sus cheques y tal. Si ya está revisando de todos modos para responder es el momento de hacer esto, debe hacer que su temporizador se active con más frecuencia para satisfacer la resolución que necesita y confiar en su verificación de cuándo debería ejecutar algo para asegurarse de que así sea. probablemente necesite algún tipo de persistencia para asegurarse de que no se ejecute dos veces (si eso es importante) en caso de que haya un apagado/reinicio y el estado de saber si ya se ha ejecutado no está aún en la memoria.

+0

Hola Dave, de la forma en que lo entendí fue que el evento del temporizador ser despedido cada x minutos una vez que lo configuré. el trabajo que estoy haciendo en mi hilo está separado de eso? así que ya sea que haya terminado mi trabajo o no, el próximo evento de 10 minutos vendría de todos modos. Para ese fin, tengo una variable "ocupada" que configuré y solo "hago trabajo" si aún no está ocupada. ¿Si eso tiene sentido? – Keith

+0

depende de qué tipo de temporizador esté utilizando y cómo lo configure. de todos modos, el punto es que los temporizadores no son lo suficientemente precisos como para contar con una ejecución de segundo a segundo durante un período de varios minutos basado en la ejecución de los eventos del temporizador. –

0

Aquí es mi opinión:

while ((DateTime.Now - lastRunTime).TotalSeconds < 600) 
    CurrentThread.Sleep(1000); 

o simplemente registrar un temporizador de Windows y ejecutar en respuesta al evento/devolución de llamada

public static void Main() 
{ 
    System.Timers.Timer aTimer = new System.Timers.Timer(); 
    aTimer.Elapsed+=new ElapsedEventHandler(OnTimedEvent); 
    // Set the Interval to 600 seconds. 
    aTimer.Interval=600000; 
    aTimer.Enabled=true; 

    Console.WriteLine("Press \'q\' to quit the sample."); 
    while(Console.Read()!='q'); 
} 

// Specify what you want to happen when the Elapsed event is raised. 
private static void OnTimedEvent(object source, ElapsedEventArgs e) 
{ 
    Console.WriteLine("10 minutes passed!"); 
} 
0

Los temporizadores no son exactos, solo aproximados. No use la lógica de "solo agregue 10 minutos". Cada vez que se dispara el temporizador, debe verificar la inclinación del tiempo y ajustar.

por ejemplo. Si dices "despiértame en 10 minutos", y te despierta en 10 minutos y 1 segundo, entonces el siguiente temporizador debe ser de 9 minutos y 59 segundos, no de 10 minutos.

Además, desea asignar su próximo temporizador al final de su lógica.

por ejemplo. supongamos que desea iniciar la tarea A cada 10 minutos y tarda 2 segundos en ejecutarse.Su temporizador se inicia y 10 minutos más tarde se despierta para ejecutar la tarea A. Empieza, termina, ahora agregas 10 minutos. Pero llevó 2 segundos ejecutar su tarea. Entonces, 10 minutos desde el momento en que se ejecutó tu código estarán sesgados por 2 segundos.

Lo que necesita hacer es predecir la próxima vez que necesite ejecutar y encontrar la diferencia entre ahora y entonces, y establecer el temporizador a esa diferencia.

+0

Pero no estoy "agregando" 10 minutos. Estoy configurando un temporizador una vez, diciéndole que dispare cada 10 minutos y luego ejecute mi código en su evento "OnFired". Si te das cuenta de lo que quiero decir. – Keith