Solo esto: ¿cómo se agrega un temporizador a una aplicación de consola C #? Sería genial si pudiera proporcionar algún ejemplo de codificación.
Solo esto: ¿cómo se agrega un temporizador a una aplicación de consola C #? Sería genial si pudiera proporcionar algún ejemplo de codificación.
Respuestas:
Eso es muy bueno, sin embargo, para simular el paso del tiempo, necesitamos ejecutar un comando que tome algo de tiempo y que esté muy claro en el segundo ejemplo.
Sin embargo, el estilo de usar un bucle for para hacer alguna funcionalidad para siempre requiere muchos recursos del dispositivo y en su lugar podemos usar el recolector de basura para hacer algo así.
Podemos ver esta modificación en el código del mismo libro 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()
. No hay nada que coleccionar. Tendría sentido si GC.KeepAlive(t)
se llamara despuésConsole.ReadLine();
Use la clase System.Threading.Timer.
System.Windows.Forms.Timer está diseñado principalmente para su uso en un solo subproceso, generalmente el subproceso de interfaz de usuario de Windows Forms.
También hay una clase System.Timers agregada al inicio del desarrollo del marco .NET. Sin embargo, generalmente se recomienda usar la clase System.Threading.Timer en su lugar, ya que de todos modos esto es solo una envoltura alrededor de System.Threading.Timer.
También se recomienda usar siempre un System.Threading.Timer estático (compartido en VB.NET) si está desarrollando un servicio de Windows y necesita un temporizador para ejecutarse periódicamente. Esto evitará la recolección de basura posiblemente prematura de su objeto de temporizador.
Aquí hay un ejemplo de un temporizador en una aplicación de consola:
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
}
}
Del libro CLR Via C # de Jeff Richter. Por cierto, este libro describe la justificación detrás de los 3 tipos de temporizadores en el Capítulo 23, muy recomendable.
Aquí está el código para crear un simple tic de temporizador de un segundo:
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);
}
}
}
Y aquí está el resultado resultante:
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
EDITAR: Nunca es una buena idea agregar bucles de giro duro al código, ya que consumen ciclos de CPU sin ganancia. En este caso, ese bucle se agregó solo para detener el cierre de la aplicación, lo que permite observar las acciones del hilo. Pero en aras de la corrección y para reducir el uso de la CPU, se agregó una simple llamada de suspensión a ese bucle.
Vamos a divertirnos un poco
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();
}
}
}
O usando Rx, corto y dulce:
static void Main()
{
Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(t => Console.WriteLine("I am called... {0}", t));
for (; ; ) { }
}
También puede usar sus propios mecanismos de temporización si desea un poco más de control, pero posiblemente menos precisión y más código / complejidad, pero aún así recomendaría un temporizador. Sin embargo, use esto si necesita tener control sobre el hilo de sincronización real:
private void ThreadLoop(object callback)
{
while(true)
{
((Delegate) callback).DynamicInvoke(null);
Thread.Sleep(5000);
}
}
sería su hilo de sincronización (modifique esto para detener cuando sea necesario y en el intervalo de tiempo que desee).
y para usar / comenzar puedes hacer:
Thread t = new Thread(new ParameterizedThreadStart(ThreadLoop));
t.Start((Action)CallBack);
La devolución de llamada es su método vacío sin parámetros al que desea llamar en cada intervalo. Por ejemplo:
private void CallBack()
{
//Do Something.
}
También puede crear el suyo propio (si no está satisfecho con las opciones disponibles).
Crear tu propia Timer
implementación es algo bastante básico.
Este es un ejemplo para una aplicación que necesitaba acceso a objetos COM en el mismo hilo que el resto de mi base de código.
/// <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();
}
}
Puede agregar eventos de la siguiente manera:
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);
Para asegurarse de que el temporizador funciona, debe crear un bucle sin fin de la siguiente manera:
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();
}
}
Ahí tienes :)
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);
}
Le sugiero que siga las pautas de Microsoft ( https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1 ).
Primero intenté usar System.Threading;
con
var myTimer = new Timer((e) =>
{
// Code
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
pero se detuvo continuamente después de ~ 20 minutos.
Con eso, probé la configuración de soluciones
GC.KeepAlive(myTimer)
o
for (; ; ) { }
}
pero no funcionaron en mi caso.
Siguiendo la documentación de Microsoft, funcionó perfectamente:
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