44 votes

System.Timers.Timer/Threading.Timer vs Thread avec WhileLoop + Thread.Sleep pour les tâches périodiques

Dans mon application, je dois envoyer des battements de cœur périodiques à une application "frère".

Est-il préférable d'utiliser System.Timers.Timer/Threading.Timer ou d'utiliser un thread avec une boucle while et un Thread.Sleep ?

L'intervalle de battement de cœur est de 1 seconde.

while(!exit)
{
   //do work
   Thread.Sleep(1000);
}

ou

myTimer.Start( () => { 
                       //do work 
                      }, 1000); //pseudo code (not actual syntax)...

32voto

Justin Niessner Points 144953

Système.Threading.Timer a mon vote.

System.Timers.Timer est destiné à être utilisé dans le cadre d'une fonctionnalité de minuterie basée sur un serveur (votre code s'exécute en tant que serveur/service sur une machine hôte plutôt que d'être exécuté par un utilisateur).

Un Thread avec une boucle While et une commande Thread.Sleep est vraiment une mauvaise idée étant donné l'existence de mécanismes de Timer plus robustes dans .NET.

23voto

LBushkin Points 60611

Minuteurs du serveur sont une créature différente des fils dormants.

D'une part, en fonction de la priorité de votre thread et de ce qui est en cours d'exécution, votre thread endormi peut ou non être réveillé et programmé pour s'exécuter à l'intervalle que vous demandez. Si l'intervalle est suffisamment long, et que la précision de la programmation n'a pas vraiment d'importance, Thread.Sleep() est un choix raisonnable.

Les minuteurs, en revanche, peuvent déclencher leurs événements sur n'importe quel thread, ce qui permet de meilleures capacités de planification. Le coût de l'utilisation des minuteries, cependant, est un peu plus de complexité dans votre code - et le fait que vous ne pouvez pas être en mesure de contrôler quel thread exécute la logique sur laquelle l'événement de minuterie se déclenche. Extrait de la documentation :

Le Timer basé sur le serveur est conçu pour l'utilisation de threads de travail dans un environnement multithread. Le serveur peuvent se déplacer entre les threads pour gérer l'événement Elapsed soulevé, ce qui permet une plus grande précision que que les chronomètres Windows pour ce qui est de lever l'événement à temps.

Une autre considération est que les minuteurs invoquent leur délégué Elapsed sur un thread ThreadPool. En fonction de la durée et/ou de la complexité de votre logique, vous pouvez ne pas vouloir l'exécuter sur le pool de threads - vous pouvez vouloir un thread dédié. Un autre facteur avec les minuteries, est que si le traitement prend suffisamment de temps, l'événement de minuterie peut être soulevé à nouveau (simultanément) sur un autre thread - ce qui peut être un problème si le code exécuté n'est pas prévu ou structuré pour la concurrence.

Ne confondez pas Minuteurs du serveur avec " Minuteurs Windows ". Ce dernier terme fait généralement référence aux messages WM_TIMER qui peuvent être envoyés à une fenêtre, permettant ainsi à une application de planifier et de répondre à un traitement minuté sur son thread principal sans dormir. Toutefois, Windows Timers peut également faire référence aux messages suivants API Win pour le timing de bas niveau (ce qui n'est pas la même chose que WM_TIMER).

21voto

johnny g Points 2472

Ni l'un ni l'autre :)

Dormir est généralement mal vu (je ne me souviens malheureusement pas des détails, mais pour l'un, il s'agit d'un "bloc" ininterrompu), et Timer sont venus avec beaucoup de bagages. Si possible, je recommande System.Threading.AutoResetEvent comme tel

// initially set to a "non-signaled" state, ie will block
// if inspected
private readonly AutoResetEvent _isStopping = new AutoResetEvent (false);

public void Process()
{
    TimeSpan waitInterval = TimeSpan.FromMilliseconds (1000);

    // will block for 'waitInterval', unless another thread,
    // say a thread requesting termination, wakes you up. if
    // no one signals you, WaitOne returns false, otherwise
    // if someone signals WaitOne returns true
    for (; !_isStopping.WaitOne (waitInterval); )
    {
        // do your thang!
    }
}

En utilisant un AutoResetEvent (ou son cousin ManualResetEvent ) garantit un vrai bloc avec une signalisation thread safe (pour des choses comme la terminaison gracieuse ci-dessus). Au pire, c'est une meilleure alternative à Sleep

J'espère que cela vous aidera :)

1voto

spender Points 51307

J'ai découvert que la seule implémentation de la minuterie qui est vraiment à l'échelle est System.Threading.Timer . Toutes les autres implémentations semblent plutôt bidon si vous avez affaire à un nombre non trivial d'éléments 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