2008-11-21 15 views
28

Estoy trabajando en un pequeño rastreador web que se ejecutará en la bandeja del sistema y rastreará un sitio web cada hora en una hora.¿Cómo puedo generar un evento cada hora (o un intervalo de tiempo específico cada hora) en .NET?

¿Cuál es la mejor forma de que .NET genere un evento cada hora o algún otro intervalo para realizar alguna tarea? Por ejemplo, quiero ejecutar un evento cada 20 minutos según la hora. El evento se levantará en:

00:20 
00:40 
01:00 
01:20 
01:40 

y así sucesivamente. La mejor manera en que puedo pensar para hacer esto es creando un ciclo en un hilo, que comprueba constantemente si el tiempo es divisible por un intervalo dado y genera un evento de devolución de llamada si se alcanza la hora. Siento que tiene que haber una mejor manera.

Yo usaría un Timer pero preferiría algo que siga un "cronograma" que se ejecute en la hora o algo por el estilo.

¿No es posible configurar mi aplicación en el programador de tareas de Windows?

ACTUALIZACIÓN:
estoy añadiendo mi algoritmo para calcular el intervalo de tiempo de un temporizador. Este método toma un parámetro "minute", que es a qué hora el temporizador debe activar un tic. Por ejemplo, si el parámetro "minute" es 20, entonces el temporizador marcará los intervalos en el horario anterior.

int CalculateTimerInterval(int minute) 
{ 
    if (minute <= 0) 
     minute = 60; 
    DateTime now = DateTime.Now; 

    DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1); 

    TimeSpan interval = future - now; 

    return (int)interval.TotalMilliseconds; 
} 

Este código se utiliza de la siguiente manera:

static System.Windows.Forms.Timer t; 
const int CHECK_INTERVAL = 20; 


static void Main() 
{ 
    t = new System.Windows.Forms.Timer(); 
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL); 
    t.Tick += new EventHandler(t_Tick); 
    t.Start(); 
} 

static void t_Tick(object sender, EventArgs e) 
{ 
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL); 
} 

Respuesta

31

System.Timers.Timer. Si desea ejecutar en momentos específicos del día, tendrá que calcular cuánto tiempo pasará hasta la próxima vez y establecerlo como su intervalo.

Esta es solo la idea básica. Dependiendo de qué tan preciso debe ser, puede hacer más.

int minutes = DateTime.Now.Minute; 
int adjust = 10 - (minutes % 10); 
timer.Interval = adjust * 60 * 1000; 
+4

convenidas - temporizadores son el camino a seguir. Los "bucles que controlan" son solo otra forma de decir "sondeo" y la votación mata. Usar un temporizador es tu mejor opción. – Keithius

+0

Se realizó una edición, pero hasta que se apruebe: timer.Interval = adjust * 60 * 1000. El intervalo es en milisegundos. Consulte [Intervalo de temporizador] (http://msdn.microsoft.com/en-us/library/system.timers.timer.interval.aspx) para obtener más información –

+0

Solo como referencia, si desea que el evento se active cada diez minutos, el intervalo tendrá que establecerse en 10 minutos después de que el evento transcurrido haya sido disparado por primera vez. De lo contrario, el evento continuará disparando a cualquier valor en el que se haya establecido el Intervalo inicial (10 - (minutos% 10)). – Erresen

1

System.Windows.Forms.Timer (o System.Timers.Timer)

pero desde ahora usted dice que no quiere para usar Temporizadores, puede ejecutar un proceso de espera ligero en otro hilo (verifique el tiempo, espere unos segundos, vuelva a verificar el tiempo ...) o cree un componente que genere un evento (usando un proceso de espera liviano) en ciertos horarios programados o intervalos

11

Usted puede encontrar ayuda de Quartz.net http://quartznet.sourceforge.net/

+1

Quartz.net parece una biblioteca increíble para usar, pero para la pequeña aplicación que estoy creando creo que es un poco exagerada (mi aplicación tiene menos de 500 líneas de código). –

+3

Incluso con una aplicación pequeña, Quartz es muy flexible y agrega muy poca sobrecarga en términos de líneas de código. Se trata de seis líneas de código para la inicialización y la programación de un trabajo programado. –

+0

cualquier muestra pequeña y fácil? Lo descargo y tengo muchos códigos, necesito algo simple y fácil – Kiquenet

4

Aquí es un ejemplo de un sistema ligero usando momento hilo y una llamada desincronizado.

Sé que hay algunas desventajas, pero me gusta utilizar esto en lugar de un temporizador al iniciar un proceso de larga ejecución (como los servicios back-end programados). Dado que se ejecuta en línea en el subproceso del temporizador, no tiene que preocuparse de que se inicie de nuevo antes de que la llamada original haya finalizado. Esto podría extenderse un poco para hacer que use una serie de fechas como tiempos de activación o agregarle más habilidades. Estoy seguro de que algunos de ustedes saben algunas formas mejores.

public Form1() 
    { 
     InitializeComponent(); 

     //some fake data, obviously you would have your own. 
     DateTime someStart = DateTime.Now.AddMinutes(1); 
     TimeSpan someInterval = TimeSpan.FromMinutes(2); 

     //sample call 
     StartTimer(someStart,someInterval,doSomething); 
    } 

    //just a fake function to call 
    private bool doSomething() 
    { 
     DialogResult keepGoing = MessageBox.Show("Hey, I did something! Keep Going?","Something!",MessageBoxButtons.YesNo); 
     return (keepGoing == DialogResult.Yes); 
    } 

    //The following is the actual guts.. and can be transplanted to an actual class. 
    private delegate void voidFunc<P1,P2,P3>(P1 p1,P2 p2,P3 p3); 
    public void StartTimer(DateTime startTime, TimeSpan interval, Func<bool> action) 
    { 
     voidFunc<DateTime,TimeSpan,Func<bool>> Timer = TimedThread; 
     Timer.BeginInvoke(startTime,interval,action,null,null); 
    } 

    private void TimedThread(DateTime startTime, TimeSpan interval, Func<bool> action) 
    { 
     bool keepRunning = true; 
     DateTime NextExecute = startTime; 
     while(keepRunning) 
     { 
      if (DateTime.Now > NextExecute) 
      { 
       keepRunning = action.Invoke(); 
       NextExecute = NextExecute.Add(interval); 
      } 
      //could parameterize resolution. 
      Thread.Sleep(1000); 
     }    
    } 
1

Otra estrategia para esto sería registrar la ÚLTIMA VEZ que se ejecutó el proceso y determinar si ha transcurrido el intervalo deseado desde ese momento.En esta estrategia, codificaría su evento para disparar si el tiempo transcurrido es igual O MAYOR QUE el intervalo deseado. De esta forma, puede manejar instancias en las que los intervalos largos (por ejemplo, una vez al día) podrían perderse si la computadora fuera inactiva por alguna razón.

Así, por ejemplo:

  • lastRunDateTime = 5/2/2009 a las 8 pm
  • Quiero correr mi proceso cada 24 horas
  • En un evento de temporizador, comprobar si las 24 horas o más pasado desde la última vez que se ejecutó el proceso.
  • Si es así, ejecutar el proceso, actualizar lastRunDateTime añadiendo el intervalo deseado a la misma (24 horas en este caso, pero lo que usted necesita que sea)

Obviamente, para que esto recuperarse después de que el sistema tiene Sin embargo, tendrá que almacenar lastRunDateTime en un archivo o base de datos en algún lugar para que el programa pueda continuar donde lo dejó en la recuperación.

-1

Mi objetivo es ejecutar una importación alrededor de las 03:00 todas las noches.

Aquí es mi enfoque, utilizando System.Timers.Timer:

private Timer _timer; 
private Int32 _hours = 0; 
private Int32 _runAt = 3; 

protected override void OnStart(string[] args) 
{ 
    _hours = (24 - (DateTime.Now.Hour + 1)) + _runAt; 
    _timer = new Timer(); 
    _timer.Interval = _hours * 60 * 60 * 1000; 
    _timer.Elapsed += new ElapsedEventHandler(Tick); 
    _timer.Start(); 
} 

void Tick(object sender, ElapsedEventArgs e) 
{ 
    if (_hours != 24) 
    { 
     _hours = 24; 
     _timer.Interval = _hours * 60 * 60 * 1000; 
    } 

    RunImport(); 
} 
+0

Si está ejecutando una importación diaria, esta sería una mala idea. Es mejor utilizar una tarea programada de Windows para garantizar que se ejecute una importación a las 3:00 a.m. Su enfoque tiene varios errores potencialmente peligrosos asociados a él según sus requisitos. –

+0

Dan, por favor, elabore. ¿Qué puede salir mal? – hey

+0

Si se cambia la hora en la computadora, no se iniciará exactamente a las 3 a.m., o si se ejecuta en el horario de verano, sería una hora de descanso. Si se está ejecutando en el contexto de un grupo de aplicaciones de IIS, tampoco es probable que se ejecute. Mi ejemplo original solo tenía un temporizador de 20 minutos, por lo que el margen de error era de unos pocos minutos si algo salía mal, y estaba en una aplicación de escritorio, por lo que era probable que siguiera funcionando, sin embargo, incluso mi ejemplo original sería más adecuado para una tarea programada de Windows. –

Cuestiones relacionadas