31 votes

Comment puis-je déclencher un événement toutes les heures (ou un intervalle de temps spécifique toutes les heures) en .NET ?

Je travaille sur un petit robot d'exploration du Web qui fonctionnera dans la barre d'état système et explorera un site Web toutes les heures.

Quelle est la meilleure façon de faire en sorte que .NET déclenche un événement toutes les heures ou à un autre intervalle pour effectuer une tâche. Par exemple, je veux lancer un événement toutes les 20 minutes en fonction de l'heure. L'événement serait déclenché à :

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

et ainsi de suite. Le meilleur moyen auquel je pense pour faire cela est de créer une boucle sur un thread, qui vérifie constamment si le temps est divisible par un intervalle donné et soulève un événement de rappel si le temps est atteint. Je pense qu'il doit y avoir un meilleur moyen.

J'utiliserais un Timer mais je préférerais quelque chose qui suive un "programme" qui fonctionne à l'heure ou quelque chose de ce genre.

Est-ce possible sans configurer mon application dans le planificateur de tâches de Windows ?

UPDATE :
J'ajoute mon algorithme pour calculer l'intervalle de temps d'une minuterie. Cette méthode prend un " minute Le paramètre " " indique l'heure à laquelle le minuteur doit déclencher un tic-tac. Par exemple, si le paramètre " minute "est 20, alors la minuterie fonctionnera aux intervalles indiqués dans le calendrier ci-dessus.

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;
}

Ce code est utilisé comme suit :

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);
}

31voto

tvanfosson Points 268301

System.Timers.Timer . Si vous souhaitez courir à des moments précis de la journée, vous devrez déterminer le temps qui reste jusqu'à la prochaine heure et définir cet intervalle.

C'est juste l'idée de base. En fonction de la précision dont vous avez besoin, vous pouvez en faire plus.

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

4 votes

Je suis d'accord - les minuteurs sont la solution. Les "boucles qui vérifient" sont juste une autre façon de dire "sondage", et le sondage tue. L'utilisation d'un timer est votre meilleure option.

0 votes

J'ai fait une modification, mais jusqu'à ce qu'elle soit approuvée : timer.Interval = adjust * 60 * 1000. L'intervalle est en millisecondes. Voir Intervalle de temps pour plus de détails

0 votes

À titre de référence, si vous souhaitez que l'événement se déclenche toutes les dix minutes, l'intervalle devra être défini à 10 minutes après le premier déclenchement de l'événement Elapsed. Sinon, l'événement continuera à se déclencher au rythme de l'intervalle initial (10 - (minutes % 10)).

11voto

suhair Points 5223

Vous pouvez trouver de l'aide sur Quartz.net. http://quartznet.sourceforge.net/

1 votes

Quartz.net semble être une bibliothèque géniale à utiliser, mais pour la petite application que je réalise, je pense que c'est un peu exagéré (mon application fait moins de 500 lignes de code).

3 votes

Même avec une petite application, Quartz est très flexible et ajoute très peu de lignes de code. Il faut compter environ six lignes de code pour l'initialisation et la programmation d'un travail programmé.

0 votes

Un échantillon petit et facile ? ? Je l'ai téléchargé et j'ai beaucoup de code, j'ai besoin de quelque chose de simple et facile.

3voto

Xenophile Points 676

Voici un exemple de système léger utilisant la synchronisation des threads et un appel asynchrone.

Je sais qu'il y a quelques inconvénients, mais j'aime utiliser cette méthode à la place d'un timer pour lancer un processus long (comme les services backend planifiés). Puisqu'il s'exécute en ligne dans le thread du timer, vous n'avez pas à vous inquiéter qu'il soit relancé avant que l'appel original ne soit terminé. Il est possible de l'étendre considérablement en utilisant un tableau de dates comme heures de déclenchement ou en lui ajoutant d'autres capacités. Je suis sûr que certains d'entre vous connaissent de meilleures méthodes.

    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);
        }            
    }

2voto

Casey Gay Points 149

Une autre stratégie consisterait à enregistrer la DERNIÈRE FOIS que le processus a été exécuté et à déterminer si l'intervalle souhaité s'est écoulé depuis ce moment. Dans cette stratégie, vous coderez votre événement pour qu'il se déclenche si le temps écoulé est égal OU SUPÉRIEUR à l'intervalle souhaité. De cette façon, vous pouvez gérer les cas où de longs intervalles (une fois par jour, par exemple) pourraient être manqués si l'ordinateur était en panne pour une raison quelconque.

Donc, par exemple :

  • lastRunDateTime = 5/2/2009 à 20h00
  • Je veux exécuter mon processus toutes les 24 heures
  • Lors d'un événement de minuterie, vérifiez si 24 heures OU PLUS se sont écoulées depuis la dernière exécution du processus.
  • Si oui, exécutez le processus, mettez à jour lastRunDateTime en y ajoutant l'intervalle souhaité (24 heures dans ce cas, mais ce que vous voulez)

Évidemment, pour que le programme puisse se rétablir après une panne du système, vous devrez stocker lastRunDateTime dans un fichier ou une base de données quelque part afin que le programme puisse reprendre là où il s'est arrêté au moment du rétablissement.

1voto

Steven A. Lowe Points 40596

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

mais puisque vous dites maintenant que vous ne voulez pas utiliser les timers, vous pouvez exécuter un processus d'attente léger sur un autre thread (vérifier l'heure, dormir quelques secondes, vérifier l'heure à nouveau...) ou créer un composant qui déclenche un événement (en utilisant un processus d'attente léger) à certains moments ou intervalles programmés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X