Juste ceci - Comment ajouter une minuterie à une application console C #? Ce serait formidable si vous pouviez fournir un exemple de codage.
Juste ceci - Comment ajouter une minuterie à une application console C #? Ce serait formidable si vous pouviez fournir un exemple de codage.
Réponses:
C'est très bien, cependant, pour simuler le temps qui passe, nous devons exécuter une commande qui prend du temps et c'est très clair dans le deuxième exemple.
Cependant, le style d'utilisation d'une boucle for pour faire certaines fonctionnalités prend pour toujours beaucoup de ressources de l'appareil et à la place, nous pouvons utiliser le Garbage Collector pour faire quelque chose comme ça.
On peut voir cette modification dans le code du même livre CLR Via C # Third Ed.
using System;
using System.Threading;
public static class Program {
public static void Main() {
// Create a Timer object that knows to call our TimerCallback
// method once every 2000 milliseconds.
Timer t = new Timer(TimerCallback, null, 0, 2000);
// Wait for the user to hit <Enter>
Console.ReadLine();
}
private static void TimerCallback(Object o) {
// Display the date/time when this method got called.
Console.WriteLine("In TimerCallback: " + DateTime.Now);
// Force a garbage collection to occur for this demo.
GC.Collect();
}
}
GC.Collect()
. Il n'y a rien à collecter. Cela aurait du sens, si GC.KeepAlive(t)
était appelé aprèsConsole.ReadLine();
Utilisez la classe System.Threading.Timer.
System.Windows.Forms.Timer est principalement conçu pour être utilisé dans un seul thread, généralement le thread d'interface utilisateur Windows Forms.
Il existe également une classe System.Timers ajoutée au début du développement du framework .NET. Cependant, il est généralement recommandé d'utiliser la classe System.Threading.Timer à la place car il ne s'agit que d'un wrapper autour de System.Threading.Timer de toute façon.
Il est également recommandé de toujours utiliser un System.Threading.Timer statique (partagé dans VB.NET) si vous développez un service Windows et que vous avez besoin d'une minuterie pour s'exécuter périodiquement. Cela évitera éventuellement un garbage collection prématuré de votre objet timer.
Voici un exemple de minuterie dans une application console:
using System;
using System.Threading;
public static class Program
{
public static void Main()
{
Console.WriteLine("Main thread: starting a timer");
Timer t = new Timer(ComputeBoundOp, 5, 0, 2000);
Console.WriteLine("Main thread: Doing other work here...");
Thread.Sleep(10000); // Simulating other work (10 seconds)
t.Dispose(); // Cancel the timer now
}
// This method's signature must match the TimerCallback delegate
private static void ComputeBoundOp(Object state)
{
// This method is executed by a thread pool thread
Console.WriteLine("In ComputeBoundOp: state={0}", state);
Thread.Sleep(1000); // Simulates other work (1 second)
// When this method returns, the thread goes back
// to the pool and waits for another task
}
}
Extrait du livre CLR Via C # de Jeff Richter. En passant, ce livre décrit la logique derrière les 3 types de minuteries dans le chapitre 23, fortement recommandé.
Voici le code pour créer un simple tick de minuterie d'une seconde:
using System;
using System.Threading;
class TimerExample
{
static public void Tick(Object stateInfo)
{
Console.WriteLine("Tick: {0}", DateTime.Now.ToString("h:mm:ss"));
}
static void Main()
{
TimerCallback callback = new TimerCallback(Tick);
Console.WriteLine("Creating timer: {0}\n",
DateTime.Now.ToString("h:mm:ss"));
// create a one second timer tick
Timer stateTimer = new Timer(callback, null, 0, 1000);
// loop here forever
for (; ; )
{
// add a sleep for 100 mSec to reduce CPU usage
Thread.Sleep(100);
}
}
}
Et voici le résultat obtenu:
c:\temp>timer.exe
Creating timer: 5:22:40
Tick: 5:22:40
Tick: 5:22:41
Tick: 5:22:42
Tick: 5:22:43
Tick: 5:22:44
Tick: 5:22:45
Tick: 5:22:46
Tick: 5:22:47
EDIT: Ce n'est jamais une bonne idée d'ajouter des boucles hard spin dans le code car elles consomment des cycles CPU sans gain. Dans ce cas, cette boucle a été ajoutée juste pour empêcher l'application de se fermer, ce qui permet d'observer les actions du thread. Mais par souci d'exactitude et pour réduire l'utilisation du processeur, un simple appel Sleep a été ajouté à cette boucle.
Permet de s'amuser un peu
using System;
using System.Timers;
namespace TimerExample
{
class Program
{
static Timer timer = new Timer(1000);
static int i = 10;
static void Main(string[] args)
{
timer.Elapsed+=timer_Elapsed;
timer.Start(); Console.Read();
}
private static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
i--;
Console.Clear();
Console.WriteLine("=================================================");
Console.WriteLine(" DEFUSE THE BOMB");
Console.WriteLine("");
Console.WriteLine(" Time Remaining: " + i.ToString());
Console.WriteLine("");
Console.WriteLine("=================================================");
if (i == 0)
{
Console.Clear();
Console.WriteLine("");
Console.WriteLine("==============================================");
Console.WriteLine(" B O O O O O M M M M M ! ! ! !");
Console.WriteLine("");
Console.WriteLine(" G A M E O V E R");
Console.WriteLine("==============================================");
timer.Close();
timer.Dispose();
}
GC.Collect();
}
}
}
Ou en utilisant Rx, court et doux:
static void Main()
{
Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(t => Console.WriteLine("I am called... {0}", t));
for (; ; ) { }
}
Vous pouvez également utiliser vos propres mécanismes de chronométrage si vous voulez un peu plus de contrôle, mais peut-être moins de précision et plus de code / complexité, mais je recommanderais quand même un minuteur. Utilisez ceci si vous avez besoin de contrôler le thread de synchronisation réel:
private void ThreadLoop(object callback)
{
while(true)
{
((Delegate) callback).DynamicInvoke(null);
Thread.Sleep(5000);
}
}
serait votre fil de synchronisation (modifiez-le pour qu'il s'arrête lorsque cela est nécessaire, et à n'importe quel intervalle de temps souhaité).
et pour utiliser / démarrer, vous pouvez faire:
Thread t = new Thread(new ParameterizedThreadStart(ThreadLoop));
t.Start((Action)CallBack);
Le rappel est votre méthode sans paramètre void que vous souhaitez appeler à chaque intervalle. Par exemple:
private void CallBack()
{
//Do Something.
}
Vous pouvez également créer le vôtre (si vous n'êtes pas satisfait des options disponibles).
Créer votre propre Timer
implémentation est assez basique.
Ceci est un exemple pour une application qui avait besoin d'un accès aux objets COM sur le même thread que le reste de ma base de code.
/// <summary>
/// Internal timer for window.setTimeout() and window.setInterval().
/// This is to ensure that async calls always run on the same thread.
/// </summary>
public class Timer : IDisposable {
public void Tick()
{
if (Enabled && Environment.TickCount >= nextTick)
{
Callback.Invoke(this, null);
nextTick = Environment.TickCount + Interval;
}
}
private int nextTick = 0;
public void Start()
{
this.Enabled = true;
Interval = interval;
}
public void Stop()
{
this.Enabled = false;
}
public event EventHandler Callback;
public bool Enabled = false;
private int interval = 1000;
public int Interval
{
get { return interval; }
set { interval = value; nextTick = Environment.TickCount + interval; }
}
public void Dispose()
{
this.Callback = null;
this.Stop();
}
}
Vous pouvez ajouter des événements comme suit:
Timer timer = new Timer();
timer.Callback += delegate
{
if (once) { timer.Enabled = false; }
Callback.execute(callbackId, args);
};
timer.Enabled = true;
timer.Interval = ms;
timer.Start();
Window.timers.Add(Environment.TickCount, timer);
Pour vous assurer que la minuterie fonctionne, vous devez créer une boucle sans fin comme suit:
while (true) {
// Create a new list in case a new timer
// is added/removed during a callback.
foreach (Timer timer in new List<Timer>(timers.Values))
{
timer.Tick();
}
}
Voilà :)
public static void Main()
{
SetTimer();
Console.WriteLine("\nPress the Enter key to exit the application...\n");
Console.WriteLine("The application started at {0:HH:mm:ss.fff}", DateTime.Now);
Console.ReadLine();
aTimer.Stop();
aTimer.Dispose();
Console.WriteLine("Terminating the application...");
}
private static void SetTimer()
{
// Create a timer with a two second interval.
aTimer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
e.SignalTime);
}
Je vous suggère de suivre les directives Microsoft ( https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1 ).
J'ai d'abord essayé d'utiliser System.Threading;
avec
var myTimer = new Timer((e) =>
{
// Code
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
mais il s'est arrêté en continu après ~ 20 minutes.
Avec ça, j'ai essayé le réglage des solutions
GC.KeepAlive(myTimer)
ou
for (; ; ) { }
}
mais ils n'ont pas fonctionné dans mon cas.
Suivant la documentation Microsoft, cela a parfaitement fonctionné:
using System;
using System.Timers;
public class Example
{
private static Timer aTimer;
public static void Main()
{
// Create a timer and set a two second interval.
aTimer = new System.Timers.Timer();
aTimer.Interval = 2000;
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
// Have the timer fire repeated events (true is the default)
aTimer.AutoReset = true;
// Start the timer
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program at any time... ");
Console.ReadLine();
}
private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}
// The example displays output like the following:
// Press the Enter key to exit the program at any time...
// The Elapsed event was raised at 5/20/2015 8:48:58 PM
// The Elapsed event was raised at 5/20/2015 8:49:00 PM
// The Elapsed event was raised at 5/20/2015 8:49:02 PM
// The Elapsed event was raised at 5/20/2015 8:49:04 PM
// The Elapsed event was raised at 5/20/2015 8:49:06 PM