Some system development problems may require us to perform tasks at regular intervals. Such tasks may include updating user interfaces and data or other recurring tasks. To ensure we address this need, C# provides the PeriodicTimer class, which was introduced in .NET 6.
In this article, we will delve into its functionalities and usage, exploring how it simplifies the implementation of periodic operations in C#.
Without further ado, let’s begin!
How Does the PeriodicTimer Class Work in C#?
First, let’s define some variables, which we are going to use with our example:
private readonly PeriodicTimer _periodicTimer; private readonly CancellationTokenSource _cancellationToken = new(); private Task? _task; private int _size;
Here, we define a PeriodicTimer
variable, which we will instantiate later. Also, we define and initialize a CancellationTokenSource
variable, which comes in handy when defining the logic we are going to use to terminate a recurring nullable Task
. Finally, since we want to create arrays of random numbers, the _size
variable holds the number of elements we want to create.
Second, let’s create a constructor to initialize our _periodicTimer
and the _size
of the arrays we want to create:
public PeriodicTimerMethods(TimeSpan timeSpan, int size) { _periodicTimer = new PeriodicTimer(timeSpan); _size = size; }
Next, let’s create a function to carry out a task, such as creating a random array of integers, which we need to time:
public static int[] CreateRandomArray(int size) { var array = new int[size]; for (int i = 0; i < size; i++) { array[i] = Random.Shared.Next(); } return array; }
The method returns an array of random integers of a given size.
After that, let’s implement a method that invokes CreateRandomArray()
and a PeriodicTimer
instance:
private async Task RandomArrayTimerAsync() { try { var stopWatch = System.Diagnostics.Stopwatch.StartNew(); var numberOfArrays = 1; while (await _periodicTimer.WaitForNextTickAsync(_cancellationToken.Token)) { var array = CreateRandomArray(_size); foreach (var item in array) { Console.WriteLine(item); } Console.WriteLine($"Created {numberOfArrays++} arrays in {stopWatch.Elapsed.Seconds}s"); Console.WriteLine(DateTime.Now.ToString("O")); } } catch(OperationCanceledException) { } }
Here, we want to check how many CreateRandomArray()
instances we can create and display before the user cancels the task. The WaitForNextTickAsnyc()
method waits for the next tick of the timer or for the timer to be terminated. Also, we define a Stopwatch instance to track how long it takes to invoke the method and print its elements.
Next, let’s create two helper methods to initiate and terminate the task:
public void Start() { _task = RandomArrayTimerAsync(); } public async Task StopTaskAsync() { if (_task is null) { return; } _cancellationToken.Cancel(); await _task; _cancellationToken.Dispose(); Console.WriteLine("The array task was canceled"); }
In the StopTaskAsync()
method, we invoke the Cancel()
method, which in turn sets the IsCancellationRequested
property to true
. We also allow any pending tasks to be completed before disposing of the object to free up resources.
In the main program, we can verify that our solution works as it should:
Console.WriteLine("Enter array size"); var numOfElements = Convert.ToInt32(Console.ReadLine()); var timerTask = new PeriodicTimerMethods(TimeSpan.FromSeconds(1), numOfElements); timerTask.Start(); Console.WriteLine("Press any button to terminate the task"); Console.ReadKey(); await timerTask.StopTaskAsync();
Finally, let’s see the program’s output when we execute it:
Enter array size 5 Press any button to terminate the task 479374939 697289253 1550136409 1551055180 1617676033 Created 1 arrays in 1s 2023-12-25T19:05:12.6925149+03:00 2012005036 84538657 1290408908 166230976 1357829224 Created 2 arrays in 1s 2023-12-25T19:05:13.6871240+03:00 442474362 1672553469 935280249 1896142986 1107451607 Created 3 arrays in 3s 2023-12-25T19:05:14.7019991+03:00 The array task was canceled
We can see that we can create random arrays and output them while displaying the elapsed time.
Why Use the PeriodicTimer in C#?
To start with, it is pretty simple to implement. The PeriodicTimer
class achieves this by simplifying setting up and managing timers.
On top of its simplicity, we can see that the PeriodicTimer
class is beneficial because of its precise timing, as it maintains a more accurate interval between successive invocations than other timing mechanisms.
Finally, we can implement the PeriodicTimer
class in situations where cancellation is critical. For example, we can cancel a timer before it completes its intended executions, i.e., when conditions change and we need to halt the operation.
Other Timers in C#
Besides the PeriodicTimer
class, other timer classes are also available in .NET. System.Timers.Timer class is event-based, generating an event after a set interval and providing options for creating recurring events. This class is ideal for creating server-based or service components that we intend to consume in multithreaded applications. Besides, the class has no user interface and is never visible at runtime.
Another timer in .NET is System.Threading.Timer
, which works by executing a single callback on a thread pool at regular intervals. We cannot alter the callback method when we instantiate the timer. Just like the System.Timers.Timer
class, System.Threading.Timer
is also ideal for server-based or service components in multithreaded applications. It doesn’t have a user interface and is never visible at runtime.
The System.Windows.Forms.Timer
class is present in Windows Forms applications and fires events at regular intervals. Unlike the first two classes, this class is ideal for single-threaded environments. Finally, we can take advantage of the System.Web.UI.Timer
class in Web UI applications, which initiates asynchronous or synchronous postbacks at set intervals.
The PeriodicTimer
class is superior to these other classes, as it has specific support for cancellation. Besides, it does not rely on callbacks and is less susceptible to memory leaks, making it a natural pick over the other timers.
Conclusion
In this article, we learn how to use the PeriodicTimer class in C#. Moreover, we can see that its simplicity, precise timing, and cancellation capabilities make it a valuable tool for scenarios requiring repetitive tasks. Have you implemented the PeriodicTimer class in your applications? Let us know in the comments section below.