J'ai un objet minuterie. Je veux qu'il soit exécuté toutes les minutes. Plus précisément, il doit exécuter une OnCallBack
méthode et devient inactif lorsqu'une OnCallBack
méthode est en cours d'exécution. Une fois qu'une OnCallBack
méthode se termine, elle (a OnCallBack
) redémarre une minuterie.
Voici ce que j'ai en ce moment:
private static Timer timer;
private static void Main()
{
timer = new Timer(_ => OnCallBack(), null, 0, 1000 * 10); //every 10 seconds
Console.ReadLine();
}
private static void OnCallBack()
{
timer.Change(Timeout.Infinite, Timeout.Infinite); //stops the timer
Thread.Sleep(3000); //doing some long operation
timer.Change(0, 1000 * 10); //restarts the timer
}
Cependant, cela semble ne pas fonctionner. Il fonctionne très vite toutes les 3 secondes. Même si augmenter une période (1000 * 10). On dirait que ça ferme les yeux sur1000 * 10
Qu'ai-je fait de mal?
Timer.Change
: "Si dueTime vaut zéro (0), la méthode de rappel est appelée immédiatement.". On dirait que c'est nul pour moi.Réponses:
Ce n'est pas l'utilisation correcte de System.Threading.Timer. Lorsque vous instanciez le minuteur, vous devez presque toujours effectuer les opérations suivantes:
Cela demandera au chronomètre de ne cocher qu'une seule fois lorsque l'intervalle est écoulé. Ensuite, dans votre fonction de rappel, vous modifiez la minuterie une fois le travail terminé, pas avant. Exemple:
Il n'y a donc pas besoin de mécanismes de verrouillage car il n'y a pas de concurrence. La minuterie déclenchera le prochain rappel après que l'intervalle suivant se soit écoulé + le temps de l'opération longue.
Si vous devez exécuter votre minuterie à exactement N millisecondes, je vous suggère de mesurer le temps de l'opération de longue durée à l'aide du chronomètre, puis d'appeler la méthode Change de manière appropriée:
Je fortement encourage tous ceux qui font .NET et utilise le CLR qui n'a pas lu le livre de Jeffrey Richter - CLR via C # , lire est le plus tôt possible. Les minuteries et les pools de threads y sont expliqués en détail.
la source
private void Callback( Object state ) { // Long running operation _timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite ); }
.Callback
peut être appelé à nouveau avant qu'une opération ne soit terminée.Long running operation
pourrait prendre beaucoup plus de temps alorsTIME_INTERVAL_IN_MILLISECONDS
. Que se passerait-il alors?ThreadPool
, si vous passez le chronomètre? Je pense à un scénario dans lequel un nouveau thread est généré pour faire un travail à un certain intervalle - puis relégué dans le pool de threads une fois terminé.Il n'est pas nécessaire d'arrêter la minuterie, voir la belle solution de ce post :
"Vous pouvez laisser le chronomètre continuer à déclencher la méthode de rappel, mais envelopper votre code non réentrant dans un Monitor.TryEnter / Exit. Inutile d'arrêter / redémarrer le chronomètre dans ce cas; les appels qui se chevauchent n'acquièrent pas le verrou et ne reviennent pas immédiatement."
la source
L'utilisation est-elle
System.Threading.Timer
obligatoire?Sinon,
System.Timers.Timer
a des méthodes pratiquesStart()
etStop()
(et uneAutoReset
propriété que vous pouvez définir sur false, de sorte que leStop()
n'est pas nécessaire et que vous appelez simplementStart()
après l'exécution).la source
Je ferais juste:
Et ignorez le paramètre de période, car vous essayez de contrôler la périodicité vous-même.
Votre code d'origine s'exécute aussi vite que possible, car vous continuez à spécifier
0
ledueTime
paramètre. DeTimer.Change
:la source
Change()
méthode?si vous aimez utiliser un fil de boucle à l'intérieur ...
la source