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#.

To download the source code for this article, you can visit our GitHub repository.

Without further ado, let’s begin!

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

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. 

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!