Просто так - як додати таймер до консольного додатка C #? Було б чудово, якби ви могли надати приклад кодування.
Просто так - як додати таймер до консольного додатка C #? Було б чудово, якби ви могли надати приклад кодування.
Відповіді:
Це дуже приємно, однак для того, щоб імітувати деякий час, нам потрібно запустити команду, яка потребує певного часу, і це зрозуміло у другому прикладі.
Однак стиль використання циклу for цикл, щоб виконувати певну функціональність назавжди, займає багато ресурсів пристрою, і замість цього ми можемо використовувати Garbage Collector, щоб зробити щось подібне.
Цю модифікацію ми можемо побачити в коді з тієї ж книги 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()
. Збирати нічого немає. Було б сенс, якби GC.KeepAlive(t)
викликали післяConsole.ReadLine();
Використовуйте клас System.Threading.Timer.
System.Windows.Forms.Timer розроблений в основному для використання в одному потоці, як правило, потоці інтерфейсу Windows Forms.
Існує також клас System.Timers, який було додано на початку розвитку системи .NET. Однак зазвичай рекомендується використовувати клас System.Threading.Timer, оскільки це просто обгортка навколо System.Threading.Timer.
Також рекомендується завжди використовувати статичну (поділяється у VB.NET) System.Threading.Timer, якщо ви розробляєте службу Windows і потребуєте періодичного запуску таймера. Це дозволить уникнути передчасного збирання сміття об’єкта таймера.
Ось приклад таймера в консольному додатку:
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
}
}
З книги CLR Via C # Джеффа Ріхтера. До речі, ця книга описує обґрунтування трьох типів таймерів у главі 23, настійно рекомендується.
Ось код для створення простої галочки таймера:
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);
}
}
}
І ось отриманий результат:
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: Ніколи не є ідеєю додавати жорсткі петлі спіну в код, оскільки вони споживають цикли процесора без жодних вигод. У цьому випадку цикл додавали лише для того, щоб зупинити програму не закриватися, дозволяючи спостерігати за діями потоку. Але задля правильності та зменшення використання процесора до цього циклу було додано простий дзвінок Sleep.
Давайте трохи розважимось
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();
}
}
}
Або використовуючи короткий і солодкий Rx:
static void Main()
{
Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(t => Console.WriteLine("I am called... {0}", t));
for (; ; ) { }
}
Ви також можете використовувати свої власні механізми синхронізації, якщо хочете трохи більше контролю, але, можливо, меншої точності та більшої кількості коду / складності, але я все-таки рекомендую таймер. Використовуйте це, хоча якщо вам потрібно мати контроль над фактичним потоком синхронізації:
private void ThreadLoop(object callback)
{
while(true)
{
((Delegate) callback).DynamicInvoke(null);
Thread.Sleep(5000);
}
}
буде вашим потоком синхронізації (модифікуйте це, щоб зупинитись при повторному користуванні та в будь-який часовий інтервал).
і використовувати / запустити ви можете:
Thread t = new Thread(new ParameterizedThreadStart(ThreadLoop));
t.Start((Action)CallBack);
Зворотний виклик - це недійсний метод без параметрів, який потрібно викликати на кожному інтервалі. Наприклад:
private void CallBack()
{
//Do Something.
}
Ви також можете створити свій власний (якщо незадоволений наявними параметрами).
Створення власної Timer
реалізації - це досить основні речі.
Це приклад для програми, якій потрібен доступ до COM-об’єктів у тому ж потоці, що й решта моєї бази даних.
/// <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();
}
}
Ви можете додати події наступним чином:
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);
Щоб переконатися, що таймер працює, вам потрібно створити нескінченний цикл наступним чином:
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();
}
}
Ось у вас це є :)
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);
}
Я пропоную вам дотримуватися інструкцій Microsoft ( https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1 ).
Я вперше спробував використовувати System.Threading;
с
var myTimer = new Timer((e) =>
{
// Code
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
але він постійно припинявся через ~ 20 хвилин.
З цим я спробував налаштування рішень
GC.KeepAlive(myTimer)
або
for (; ; ) { }
}
але в моєму випадку вони не спрацювали.
Виконуючи документацію Microsoft, вона спрацювала чудово:
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