Using Stopwatches and Timers in .NET
Two problems that plague new programmers and seasoned professionals alike is the need to delay program execution and get an accurate time how long something takes to execute. Luckily, there are probably a few thousand ways to solve each problem. Unfortunately, most of them center around laziness (the bad kind) and unreliability. In this article, I'll attempt to show you how to implement the different Timer and Stopwatch classes in .NET to help ensure your application will work as intended for years to come. Because, let's face it, you probably aren't going to be re-factoring any time soon.
First, we'll start of with an introduction to Timers and how not to implement them. Timers allow you to control the execution of your application by being able to define when an action takes place.
I remember in my very first high-school programming class, we were instructed to move a circle from one end of the screen to the other. The problem every student eventually encountered was, the circle had already moved to the edge of the screen by the time the graphics got loaded and we didn't get to see any animation. This happened because the function that incremented the (x,y) position finished running too quickly to actually notice any movement. Obviously, this takes all of the fun out actually being able to see your circle slide across the screen so something needed to be done.
We needed to come up with a way to slow each iteration of the
increment() function so we could actually see what was going on. The idea that my teacher gave at the time was to create a blank
for loop that counted to 1000.
As you can probably imagine, this method slowed the incrementing down just enough to let a classroom full of 30 students witness their very first animated program (Hazzah!) However, even though this was a good-enough solution for a classroom, it's a horrible idea for anything that will eventually end up having more than one user.
The obvious problem with the above solution (besides that it is lazy and sloppy) is the fact that, while counting a loop from 1 to 1000 on my computer today may take one second, that same loop getting executed a year from now will run in half the time or less. Not to mention, if I wanted to convert my sweet new screen-saver-circle-moving-app to run on the iPad (assuming Mono Touch is still supported a year from now, but that's a post for another day), then what?
Now, fast forward 4 years to the end of college. Obviously, we're so much smarter than we were in high school and learned tons of new programming skills that will land us a sweet gig after graduation. Right? Let's say we're in our senior design class and we run in to a similar issue with the execution of our application. Something is just running too quickly and we need a way to slow it down a little bit. John being the teacher's pet and an overall slacker will suggest this awesome delay function he learned in high school but, you won't be convinced. You remember coding this up years ago and figure there must be a better way. So, you hop on to Google and ask how to delay execution of a function in .NET, hit "I'm feeling lucky", and copy/paste the first thing on the screen that looks like it just might do the trick. Now, you can take your neat code snippet back to the team and show them how smart you really are. Unfortunately, the snippet - while shorter in length - really isn't that much better.
//Bad Code, do not use. Thread.Sleep(1000);
Now, we're a little better off than we were in high school, but we still have issues with precision. After all, there is no guarantee that your method will wait exactly one second before executing and now you have issues with things like oversleeping (as if we don't have enough to worry about in that department in our own personal lives) or undersleeping. But, we end up using the code anyway and get through our Senior Project class relatively unscathed.
Fast forward a few years and now we're professional developers that a company relies on to come up with intelligent and well thought out solutions that won't break down when one of your customers decides to buy a new computer. What do we do now?Enter Timers
Timers allow us to accomplish the things we wanted to do in the previous two examples but can't do reliably without some help from our framework. Here, we'll look at how to use timers in .NET (the right way) so we don't have to re-live the high-school or college glory days of (noob) programming.
There are actually 3 types of timer classes in .NET:
System.Windows.Forms.Timer. Each Timer class has a specific function and is useful in its own way. Below are some examples of each type of Timer and some situations in which you might find them useful.
This Timer is a server-based timer which executes Elapsed events over a recurring interval. The key here, is that this timer generates recurring events in an application. You would use the
System.Timers.Timer Class when you need to ensure something gets executed at a specific time (like a system up-time heartbeat request). These timers work well in a multi-threaded environment since the server could technically exist anywhere.
System.Threading.Timer Class is designed to execute a method at specified intervals. It should be pointed out up-front that this timer is not actually thread-safe.
This timer is designed for an environment that involves a GUI and is single-threaded.
We've just examined ways to delay execution in a .NET application, but what if we want to measure the elapsed time between two events in our application? Fortunately, .NET provides the Stopwatch Class (
System.Diagnostics.Stopwatch) which allows us to accurately measure elapsed time in a software application.
Without the stopwatch class, you'd have to resort to something like this:
This code would do what you needed, but let's see if .NET has a way to do this a little more cleanly and reliably.
.NET's Stopwatch Class gives you the ability to accurately measure elapsed time. A Stopwatch instance can measure elapsed time over several intervals with the total elapsed time calculated by adding all of the intervals together.
The following example is a different way to get the elapsed time of program execution for the above example:
stopwatch.Elapsed result is stored as a TimeSpan Structure and is formatted as
- d = days
- hh = hours
- mm = minutes
- ss = seconds
- ff = fractions of a second
This concludes our long winded look at the different ways to delay program execution (Timers) and accurately measure elapsed execution time (Stopwatch). Next time you are faced with either of these challenges in your programming exploits, I hope that this article helps you get through it easier.
Feel free to leave a comment or follow me on Twitter here.