I´m looking for some advice about making my code more efficient. What I would like to do is to have a System.Threading.Timer that runs some job every hour or so, the job is not going to be very heavy but I would like to have a code that does not take much of resources. I plan to run this code in a windows service.
This is what I have so far.
class Program
{
private static Timer timer;
static void Main(string[] args)
{
SetTimer();
}
static void SetTimer()
{
timer = new Timer(Write);
var next = DateTime.Now.AddHours(1);
var nextSync = (int)(next - DateTime.Now).TotalMilliseconds;
timer.Change(nextSync, Timeout.Infinite);
}
static void Write(object data)
{
Console.WriteLine("foo");
SetTimer(); //Call the SetTimer again for the next run.
}
}
What do you guys think? Can I make my code more efficient?
All advice is much appreciated!
Several points:
You do not have to create a new timer every hour.
Setting the second parameter to infinite, makes you have to reload the timer manually. But... In this case, why should you?
You make a difficult calculation to create a timespan from one hours form now: now + 1 hour - now. This can solved easily.
Try this:
class Program
{
private static Timer timer = new Timer(Write, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1));
static void Main(string[] args)
{
}
static void Write(object data)
{
Console.WriteLine("foo");
}
}
This is not good, since you create and abandon a brand new timer each iteration. Move
timer = new Timer(Write);
into Main so that it only executes once, then SetTimer can reuse this single Timer object.
In WPF:
DispatcherTimer timer = new DispatcherTimer();
timer.Tick += timer_Tick;
timer.Interval = = new TimeSpan(1, 0, 0); //once an hour
timer.Start();
void timer_Tick(object sender, EventArgs e)
{
//do your updates
}
Related
I need a timer that executes every minute but i have trouble getting the timer to run at all with code that i used before. so i guess i am doing sth fundamentally wrong that is not code related but even in a just newly created Console project in visual studio community 2017 it doesn't execute the _timer_elapsed method. the console terminates immediately without errors as if it has executed every code
using System;
using System.Timers;
namespace Test
{
class Program
{
static Timer _timer;
public static void Main(string[] args)
{
var timer = new Timer(60000);
timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
timer.Enabled = true;
_timer = timer;
}
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("test");
}
}
}
what am I missing here?
You need your program to stay alive, rather than return from Main. An quick and easy way to do this is to wait for some input at the end:
public static void Main(string[] args)
{
var timer = new Timer(60000);
timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
timer.Enabled = true;
_timer = timer;
Console.ReadLine();
}
There is no such thing as a bad question.
(Though some questions show more affinity with programming, and some show less.)
If you look at your code, your main sets up a timer and then proceeds to terminate. So, of course your program exits immediately and the timer is never fired.
In order to see your timer firing, your program will need to keep running for at least as long as one period of your timer.
I'm having trouble with the following code. I have some code that calls SetTimer() and expects the user to respond before interval is reached (in
millisecs). The calling code inherit these funtions. If the user responds, then StopTimer() is called, info is displayed, StartTimer() is called, and the user is expected to respond again within the interval time period. This continues until the user fails in an answer or takes too long (goes past the interval).
The problem is the timers don't stop. They keep repeating even after I've stopped them, set their Tick event to null (by the -= method), and left its scope. I even get new storage with a new DispatcherTimer (I've done this both using the old one and a new one each time). I can't get the old Timer to go away.
What am I doing wrong?
using Windows.UI.XAML;
public DispatcherTimer GameTimer;
internal void SetTimer(int interval)
{
GameTimer = new DispatcherTimer();
GameTimer.Tick += TimerCallback;
GameTimer.Interval = new TimeSpan(0,0,0,0,interval);
GameTimer.Start();
}
internal void StopTimer()
{
GameTimer.Stop();
try
{
GameTimer.Tick -= TimerCallback;
} catch {}
}
private void TimerCallback(object sender, object e)
{
StopTimer();
// Other code
}
Thanks in advance,
-justin
Try stopping the timer by using the sender object, not the actual public timer object:
private void TimerCallback(object sender, object e) {
(sender as DispatcherTimer).Stop();
// Other code
}
As a workaround, you could do something like:
// in your class
private bool _allowExecution = false;
Then whenever you start the time set _allowExecution = true; and when you stop the timer, simply add _allowExecution = false;
The last thing will be to add a simply boolean condition on your timer execute: if (_allowExecute) //do your stuff here
Because you initialize a new DispatcherTimer everytime call SetTimer(int interval). You must stop the old DispatcherTimer instance before initialize a new one.
internal void SetTimer(int interval)
{
StopTimer();
GameTimer = new DispatcherTimer();
GameTimer.Tick += TimerCallback;
GameTimer.Interval = new TimeSpan(0,0,0,0,interval);
GameTimer.Start();
}
internal void StopTimer()
{
if(GameTimer != null)
{
GameTimer.Stop();
GameTimer.Tick -= TimerCallback;
GameTimer = null;
}
}
I want to create a background worker for a WinForm that triggers code whenever midnight rolls by.
I have an idea of how to do it, but I'm pretty sure it's not the best way to do it.
while(1==1)
{
//if Datetime.Now == midnight, execute code
//sleep(1second)
}
Use a System.Timers.Timer and at application start up just calculate the difference between DateTime.Now and DateTime.Today.AddDays(0). Then set the interval for that amount.
I actually did something just like this recently:
public static class DayChangedNotifier
{
private static Timer timer;
static DayChangedNotifier()
{
timer = new Timer(GetSleepTime());
timer.Elapsed += (o, e) =>
{
OnDayChanged(DateTime.Now.DayOfWeek);
timer.Interval = this.GetSleepTime();
};
timer.Start();
SystemEvents.TimeChanged += new EventHandler(SystemEvents_TimeChanged);
}
private static void SystemEvents_TimeChanged(object sender, EventArgs e)
{
timer.Interval = GetSleepTime();
}
private static double GetSleepTime()
{
var midnightTonight = DateTime.Today.AddDays(1);
var differenceInMilliseconds = (midnightTonight - DateTime.Now).TotalMilliseconds;
return differenceInMilliseconds;
}
private static void OnDayChanged(DayOfWeek day)
{
var handler = DayChanged;
if (handler != null)
{
handler(null, new DayChangedEventArgs(day));
}
}
public static event EventHandler<DayChangedEventArgs> DayChanged;
}
AND:
public class DayChangedEventArgs : EventArgs
{
public DayChangedEventArgs(DayOfWeek day)
{
this.DayOfWeek = day;
}
public DayOfWeek DayOfWeek { get; private set; }
}
Useage: DayChangedNotified.DayChanged += ....
Instead you could user a Timer and set the timer tick interval to be the time between Now() and midnight.
I have no idea why polling solutions were voted up when Microsoft solved this type of problem years ago by adding a windows service to handle timing. Just create a scheduled task to run the exe. No extra overhead.
you can use Quartz to schedule that. Maybe is like a cannon to kill a mosquito in this scenario, but that's is the only scheduling job framework i know and works excellent.
Don't use polling. Instead, set up a timer task, set it to fire at midnight, and add an event to process.
TimeSpan timeBetween = DateTime.Today.AddDays(1) - DateTime.Now;
System.Timers.Timer t = new System.Timers.Timer();
t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
t.Interval = 1000 * timeBetween.Seconds;
t.Start();
I'm a little confuse about why you need a WinForm, will it be running at midnight? If all you need is some sort process to run, use the windows scheduler to run it at midnight. (On XP, but I believe Win server should be similar)Control Panel -> Scheduled Tasks -> Add Scheduled Task -> Fill out the wizard. Save you a lot of coding.
I have a statusbar label and I want to show a text on my StatusBar Label for 3 seconds only
How can I do it without using threads?
public void InfoLabel(string value)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(InfoLabel), new object[] { value });
return;
}
infoLabel.Text = value;
}
Simply add timer on the end of your method:
if (!string.IsNullOrWhiteSpace(value))
{
System.Timers.Timer timer = new System.Timers.Timer(3000) { Enabled = true };
timer.Elapsed += (sender, args) =>
{
this.InfoLabel(string.Empty);
timer.Dispose();
};
}
You need to define a function that you call each time you need to display your text, inside this function you define a timer, this timer is based on System.Windows.Forms.Timer, the only difference is that its modified to hold a stopTime parameter that represents the running duration, the only thing you need to do is to put your starting code(display text) inside the MyFunction function and to put the ending code(to stop displaying text) inside the Timer_Tick function, once you call MyFunction just specify how many seconds you want it to run in the function parameter.
private void MyFunction(int durationInSeconds)
{
MyTimer timer = new MyTimer();
timer.Tick += new EventHandler(Timer_Tick);
timer.Interval = (1000) * (1); // Timer will tick every second, you can change it if you want
timer.Enabled = true;
timer.stopTime = System.DateTime.Now.AddSeconds(durationInSeconds);
timer.Start();
//put your starting code here
}
private void Timer_Tick(object sender, EventArgs e)
{
MyTimer timer = (MyTimer)sender;
if (System.DateTime.Now >= timer.stopTime)
{
timer.Stop();
//put your ending code here
}
}
the modified timer class
public class MyTimer : System.Windows.Forms.Timer
{
public System.DateTime stopTime;
public MyTimer()
{
}
}
You can use Timer to create an instance of a timer that waits for n seconds before firing the Elapsed event. In the elapsed event, you clear the label's Content.
As the timer is executed in a separate thread, the UI thread is not locked while the timer is counting i.e. you are free to perform other operations in the UI.
private delegate void NoArgDelegate();
private void StartTimer(int durationInSeconds)
{
const int milliSecondsPerSecond = 1000;
var timer = new Timer(durationInSeconds * milliSecondsPerSecond);
timer.Start();
timer.Elapsed += timer_Elapsed;
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
var clearLabelTextDelegate = new NoArgDelegate(ClearLabelText);
this.Dispatcher.BeginInvoke(clearLabelTextDelegate);
}
private void ClearLabelText()
{
this.myLabel.Content = string.Empty;
}
As I do not the rest of your code, some suggestions would be to create a lock on the timer so as to prevent more than one UI event starting the timer. In addition, the delegate and the timer instance can be made as private members of the class.
You'll always be using at least the GUI thread. If you decide to wait on that thread, no other interaction with controls is possible (ie. no buttons will work, the window will not be repainted).
Alternatively you could use a System.Windows.Forms.Timer that gives control back to the OS, or another type of timer. Either way, the "countdown" will either block user interaction or happen on another thread (under the hood).
I want to create a background worker for a WinForm that triggers code whenever midnight rolls by.
I have an idea of how to do it, but I'm pretty sure it's not the best way to do it.
while(1==1)
{
//if Datetime.Now == midnight, execute code
//sleep(1second)
}
Use a System.Timers.Timer and at application start up just calculate the difference between DateTime.Now and DateTime.Today.AddDays(0). Then set the interval for that amount.
I actually did something just like this recently:
public static class DayChangedNotifier
{
private static Timer timer;
static DayChangedNotifier()
{
timer = new Timer(GetSleepTime());
timer.Elapsed += (o, e) =>
{
OnDayChanged(DateTime.Now.DayOfWeek);
timer.Interval = this.GetSleepTime();
};
timer.Start();
SystemEvents.TimeChanged += new EventHandler(SystemEvents_TimeChanged);
}
private static void SystemEvents_TimeChanged(object sender, EventArgs e)
{
timer.Interval = GetSleepTime();
}
private static double GetSleepTime()
{
var midnightTonight = DateTime.Today.AddDays(1);
var differenceInMilliseconds = (midnightTonight - DateTime.Now).TotalMilliseconds;
return differenceInMilliseconds;
}
private static void OnDayChanged(DayOfWeek day)
{
var handler = DayChanged;
if (handler != null)
{
handler(null, new DayChangedEventArgs(day));
}
}
public static event EventHandler<DayChangedEventArgs> DayChanged;
}
AND:
public class DayChangedEventArgs : EventArgs
{
public DayChangedEventArgs(DayOfWeek day)
{
this.DayOfWeek = day;
}
public DayOfWeek DayOfWeek { get; private set; }
}
Useage: DayChangedNotified.DayChanged += ....
Instead you could user a Timer and set the timer tick interval to be the time between Now() and midnight.
I have no idea why polling solutions were voted up when Microsoft solved this type of problem years ago by adding a windows service to handle timing. Just create a scheduled task to run the exe. No extra overhead.
you can use Quartz to schedule that. Maybe is like a cannon to kill a mosquito in this scenario, but that's is the only scheduling job framework i know and works excellent.
Don't use polling. Instead, set up a timer task, set it to fire at midnight, and add an event to process.
TimeSpan timeBetween = DateTime.Today.AddDays(1) - DateTime.Now;
System.Timers.Timer t = new System.Timers.Timer();
t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
t.Interval = 1000 * timeBetween.Seconds;
t.Start();
I'm a little confuse about why you need a WinForm, will it be running at midnight? If all you need is some sort process to run, use the windows scheduler to run it at midnight. (On XP, but I believe Win server should be similar)Control Panel -> Scheduled Tasks -> Add Scheduled Task -> Fill out the wizard. Save you a lot of coding.