I need to measure an event time precisely (suppose the time between two clicks). I used a timer and set the interval to "1" and a counter inside Tick event. The problem is since there are a lot of lines in my code the Tick event does not actually happen every 1ms (maybe every 8ms or more). Is there any way to use a thread and run a 1ms-timer independently in it?
//start
long start = DateTime.Now.Ticks;
//to do something
//...
//end
long end = DateTime.Now.Ticks;
long delta = end - start;
var stopWatch = Stopwatch.StartNew();
// do something
stopWatch.Stop();
Console.WriteLine(stopWatch.ElapsedMilliseconds);
Related
I am developing an application (sort of a game helper), which sends keystrokes to a game at certain time intervals (you can specify what key will be pressed).
The problem is that I need to do the KeyPress event with a millisecond precision. After some research I found out that Thread.Sleep has a resolution of 20-50 ms and the best I could find so far was using the StopWatch() like following:
cmd_PlayJumps = new DelegateCommand(
() =>
{
ActivateWindow();
Stopwatch _timer = new Stopwatch();
Stopwatch sw = new Stopwatch();
double dElapsed = 0;
//Initial Key Press
_timer.Start();
_Keyboard.KeyPress(WindowsInput.Native.VirtualKeyCode.RETURN);
int iTotalJumps = SelectedLayout.JumpCollection.Count;
//loop through collection
for (int iJump = 0; iJump < iTotalJumps - 1; iJump++)
{
dElapsed = _timer.Elapsed.TotalMilliseconds;
sw.Restart();
while (sw.Elapsed.TotalMilliseconds < SelectedLayout.JumpCollection[iJump + 1].WaitTime -
dElapsed)
{
//wait
}
_timer.Restart();
_Keyboard.KeyPress(WindowsInput.Native.VirtualKeyCode.RETURN);
}
//final key press
_Keyboard.KeyPress(WindowsInput.Native.VirtualKeyCode.RETURN);
_timer.Stop();
_timer = null;
});
As duration of KeyPress event varies within 0.3 - 1.5 ms I also keep track of that in order to get rid of deviation.
Nonetheless, I am only able to get 60% accuracy with this code, as even the StopWatch() is not that precise (of course if my code is not incorrect).
I would like to know, how can I achieve at least 90% accuracy?
The Problem is that you need to be lucky, it all depends on how often the .Tick is reached, which will be around 0.2-2 ms depending on your hardware. It is extremely difficult to avoid this, you could try setting a high process priority to steal the CPU away to get more Ticks in.
This can be achieved with :
System.Diagnostics.Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Also try setting
while (sw.Elapsed.TotalMilliseconds <= SelectedLayout.JumpCollection[iJump + 1].WaitTime - dElapsed)
Which should save you another tick sometimes and get the accuracy up a little.
Other than that the Main issue is that windows itself is not the best Timekeeper, DateTime.Now has a tolerance of 16ms for instance and was never thought of as a "real time" operating system.
As a side note :If you really need this to be as accurate as possible I'd advise you to look into Linux.
I got it to an average timing miss of 0.448 milliseconds using a combination of Thread.Sleep and a spin waiter. Setting the thread to high priority does not change the logic, as the thread needs to be running and continuously checking the variable.
static void Main(string[] args)
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
var timespans = new List<TimeSpan>(50);
while (timespans.Count < 50)
{
var scheduledTime = DateTime.Now.AddSeconds(0.40);
Console.WriteLine("Scheduled to run at: {0:hh:mm:ss.FFFF}", scheduledTime);
var wait = scheduledTime - DateTime.Now + TimeSpan.FromMilliseconds(-50);
Thread.Sleep((int)Math.Abs(wait.TotalMilliseconds));
while (DateTime.Now < scheduledTime) ;
var offset = DateTime.Now - scheduledTime;
Console.WriteLine("Actual: {0}", offset);
timespans.Add(offset);
}
Console.WriteLine("Average delay: {0}", timespans.Aggregate((a, b) => a + b).TotalMilliseconds / 50);
Console.Read();
}
Please note that true realtime code cannot be obtained using standard, running on windows, CLR code. The garbage collector could step in, even in between loop cycles, and start collecting objects, at which point have a good chance of getting imprecise timing.
You can reduce the chance of this happening by changing the garbage collector's Latency Mode, at which point it won't do the big collections until extreme low memory situations. If this is not enough for you, consider writing the above solution in a language where better guarantees for timing are given (e.g. C++).
You could try using ElapsedTicks. It is the smallest unit that the Stopwatch can measure and you can convert the number of elapsed ticks to seconds (and fractions of seconds of course) using the Frequency property. I do not know if it is better than Elapsed.TotalMilliseconds but worth a try.
I need to display the time which will start with 0 and (which will keep running in seconds)
I need to display in a game so it will show elapsed time when playing.
as shown in the screenshot:
someone told me to do this way,
Stopwatch st = new Stopwatch();
st.Start();
and display it with
Console.WriteLine(st.Elapsed);
but its not working (seconds are not running)!
it showing as:
As I understand you just need to update your display every 1 second so why not just use a Timer which will run every 1 second and increment whatever you display on the screen. (Read about Timer here: http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx)
You can find an example here:
How to set timer in C#?
If it's a game, there must be the animation (game) loop somewhere. You should put
Console.WriteLine(st.Elapsed);
there. This way it is going to refresh correctly.
Given this is a console game: Have the Elapsed time from the StopWatch stored in a TimeSpan and then just use the Thread.Sleep(); property from System.Threading(); to simulate 1 second.
Stopwatch st = new Stopwatch();
st.Start();
while (true)
{
TimeSpan ts = st.Elapsed;
string time = String.Format("{0:00}:{1:00}:{2:00}", ts.Hours, ts.Minutes, ts.Seconds);
Console.Write("\r{0} ", time);
Thread.Sleep(1000);
}
PS: This is my first answer in this website and I hope I was helpful!
Can somebody give me a code, how to raise event when specified time is passed.
For example i have this times:
08:00 12:00 20:30 23:00
How can i subscribe to event which raising in these times?
Try the following approach:
DateTime target = ...
int interval = (int)(target - DateTime.Now).TotalMilliseconds;
var timer = new System.Timers.Timer(interval);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
The method I used for an application was to make a timer that fires every few minutes. When it gets closer to the target time (e.g. current time + interval > target time), the interval becomes smaller.
For that particular application, exact precision wasn't that important, so I didn't let the interval get smaller than 500 ms.
Finally, when you think you're close enough, you do the task you need to at that time.
Try Quartz.Net.
It can run whatever you need in specified times, one of which is the firing of an event.
use a System.Timers.Timer
Details on this can be found at MSDN.
when the event goes off, raise the event AND reprogram the timer to go off again for your next event.
I have a service that is always running, it has a timer to perform a particular action every day at 2AM.
TimeSpan runTime = new TimeSpan(2, 0, 0); // 2 AM
TimeSpan timeToFirstRun = runTime - DateTime.Now.TimeOfDay;
if (timeToFirstRun.TotalHours < 0)
{
timeToFirstRun += TimeSpan.FromDays(1.0);
}
_dailyNodalRunTimer = new Timer(
RunNodalDailyBatch,
null,
timeToFirstRun,
TimeSpan.FromDays(1.0)); //repeat event daily
That initialization code is called once when the service first starts, over the past few days I have logged when the Timer has fired:
2011-05-21 02:00:01.580
2011-05-22 02:00:03.840
...
2011-05-31 02:00:25.227
2011-06-01 02:00:27.423
2011-06-02 02:00:29.847
As you can see its drifting by 2 seconds every day, getting farther and farther from when it was supposed to fire(at 2 AM).
Am I using it wrong or is this Timer not designed to be accurate? I could recreate the timer each day, or have it fire at some small interval and repeatedly check if I want to perform the action, but that seems kind of hacky.
EDIT
I tried using System.Timers.Timer and it appears to have the same issue. The reseting the Interval is because you cant schedule the initial time before the first tick in System.Timers.Timer like you can in System.Threading.Timer
int secondsInterval = 5;
double secondsUntilRunFirstRun = secondsInterval - (DateTime.Now.TimeOfDay.TotalSeconds % secondsInterval);
var timer = new System.Timers.Timer(secondsUntilRunFirstRun * 1000.0);
timer.AutoReset = true;
timer.Elapsed += (sender, e) =>
{
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff"));
if (timer.Interval != (secondsInterval * 1000.0))
timer.Interval = secondsInterval * 1000.0;
};
timer.Start();
Produce the following times, you can see how they are drifting slightly:
06:47:40.020
06:47:45.035
06:47:50.051
...
06:49:40.215
06:49:45.223
06:49:50.232
So I guess the best approach really is to just reschedule the timer in the tick handler? The following produces a tick at a regular interval within ~15 milliseconds
double secondsUntilRunFirstRun = secondsInterval - (DateTime.Now.TimeOfDay.TotalSeconds % secondsInterval);
var timer = new System.Timers.Timer(secondsUntilRunFirstRun * 1000.0);
timer.AutoReset = false;
timer.Elapsed += (sender, e) =>
{
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff"));
timer.Interval = (secondsInterval - (DateTime.Now.TimeOfDay.TotalSeconds % secondsInterval)) * 1000.0;
};
timer.Start();
06:51:45.009
06:51:50.001
...
06:52:50.011
06:52:55.013
06:53:00.001
Don't let timer inaccuracies accumulate. Use the RTC to calculate how many ms remain until the timeout time. Sleep/setInterval to half this time. When the timer fires/sleep returns, use the RTC again to recalculate the interval left and set interval/sleep again to half-life. Repeat this loop until the remaining interval is less than 50ms. Then CPU loop on the RTC until the desired time is exceeded. Fire the event.
Rgds,
Martin
None of the timers in the .NET Framework will be accurate. There are too many variables in play. If you want a more accurate timer then take a look at multimedia timers. I have never used them over longer durations, but I suspect they are still substantially more accurate than the BCL timers.
But, I see no reason that would prohibit you from using the System.Threading.Timer class. Instead of specifying TimeSpan.FromDays(1) use Timeout.Infinite to prevent periodic signaling. You will then have to restart the timer, but you can specify 23:59:58 or 1.00:00:05 for the dueTime parameter depending on what you calculate the next due time to be to have signal at 2:00a.
By the way, the System.Timers.Timer will do no better than System.Threading.Timer. The reason is because the former actually uses the later behind the scenes anyway. System.Timers.Timer just adds a few handy features like auto resetting and marshaling the execution of the Elapsed onto an ISynchronizeInvoke hosted thread (usually a UI thread).
I think you've already realized this but if you want something to fire at a certain time of day (2AM) you'd be better off with a dedicated thread that sleeps, periodically wakes up and looks to see if it's time to run yet. A sleep around 100 milliseconds would be appropriate and would burn virtually no CPU.
Another approach would be that after you've done your daily work, you compute when to next fire based on 2AM tomorrow - DateTime.Current, etc. This may still not be as accurate as you want (I'm not sure) but at least the drift won't get worse and worse and worse.
If you need accurate timing, you'll need System.Timers.Timer class.
Also see this question: .NET, event every minute (on the minute). Is a timer the best option?
From msdn:
System.Threading.Timer is a simple,
lightweight timer ... For server-based timer functionality, you might consider using System.Timers.Timer, which raises events and has additional features.
You can also move it to Windows Task Scheduler
I am creating a clock application in C#.Net.I have images for each digits from 0-9. I have a timer in the main page constructor which ticks every seconds
DispatcherTimer tmr = new DispatcherTimer();
tmr.Interval = TimeSpan.FromSeconds(1);
tmr.Tick += new EventHandler(tmr_Tick);
tmr.Start();
void tmr_Tick(object sender, EventArgs e)
{
dt = DateTime.Now;
UpdateSecondsImages(dt);
}
private void UpdateSecondsImages(DateTime dt)
{
secondSource2 = dt.Second % 10;
secondDigit2.Source = digimgs[secondSource2];
if (secondSource2 == 0)
{
secondSource1 = dt.Second / 10;
secondDigit1.Source = digimgs[secondSource1];
}
if (secondSource1 == 0)
{
UpdateMinuteImages(dt);
}
}
But the problem I am facing now is this code may skip a second for a minute.Please suggest alternate way to make this smooth from a performance point of view.
Simple. When you set a timer to go off every second you are saying, "please sleep for at least 1 second before waking up and notifying me". In reality, you could be sleeping for much longer. Also, different timing APIs have clock drift relative to each other. The clock that timers are based on may not be the same clock that the DateTime.Now is based on.
Think of it like this - let's say you are actually be waking up once every 1.02 seconds.
Hence, every 50 seconds, you'll skip a beat in rendering. For example you'll go from waking up at "49.98" (rendered as "49") and then your next interval you are woken up at "51.00".
The simple workaround is to sleep for sometime less than 1 second. In your case, I suggest sleeping between 500-750 milliseconds instead of a full second. You can simply re-render the same time again in the case where you wakeup within the same second interval. Or as a trivial optimization, just do nothing when you've already woken up an the second count hasn't changed since previous time.
try saying:
tmr.Interval = TimeSpan.FromMilliSeconds(500);
If it's okay to show clock only when they're visible, I'd rather suggest to use CompositionTarget.Render event handler. Get current time in it and update the UI appropriately. This will not only eliminate the error but will let you render milliseconds as well :).
I highly doubt this approach impacts performance (cos() and sin() are damn fast in our days). But even if it will (you are rendering thousands of clocks), you can update UI not on every frame.
Hope this helps.
Yesterday we launched a contest with Ball Watch USA to create watches in Silverlight. I recommend using a Storyboard to rotate the second hand 360 degrees over 1 minute and set the storyboard to repeat forever. Here are some links:
The Contest
A video describing the task
The animation XAML in SL1
Updating the code to SL2