Tuesday, December 13, 2016

Handle once for many events via sliding timer.

As a developer we might have encountered many situations where we have to do certain things when something triggers but it triggers so frequently which makes our handler code run many times and it affecting performance. The functionality might be achieved by responding to last trigger. In .Net way, we can take events as triggers and if we want to handle event which is firing frequently it affects the performance.

Coming to an example for more clarity. Suppose we need to do something when the network is connected or disconnected, we can hook into the NetworkAvailabilityChanged or NetworkAddressChanged and write the code. But the network sometimes can get fluctuations, and these events may fires frequently but we don't need to respond for each event but to the last event. This is same if we want to show the MousePosition. We should only handle the last mouse move event. Not all. 

The event is firing rapidly. Need to handle the last one.

The major problem here is to identify which is the last one. In other words how much time we need to wait without any event firing to determine the last one.

This is purely the decision of the developer based on the situation. In some situations we can easily conclude that, if there is a 1 second delay the previous one was the last event. Sometimes that delay may be 5-10 seconds or can be small in milliseconds.

In short, many event firings happened but no need to handle once for all by determining a last point. This can be done using sliding timer mechanism or simple timer monitor.

Sliding timer

There is no  timer class in .Net framework called SlidingTimer. This is just a mechanism to reset the time based on triggers. If no event triggered, for a specified time, the timer ticks and the operation can be done.

When this should not be used

 If every event needs to be handled we cannot use this sliding timer mechanism. For example a sensor event or data feed where each and every event brings different data and needs to be processed.

Sample code

Below is a sample WPF implementation. This sample is trying to show the location of a window in a textblock whenever the window is moved. Since the LocationChanged event fires rapidly it uses SlidingTimer to determine when the user stops dragging the window. In other words, if the LocationChanged firing started and stops firing for 2 seconds, it the best time to update the location in textbox. First lets take a look at the consuming side.
private readonly int IdleTimeInMilliSecondsRequiredToProcessEvent = 2000;
SlidingTimer slidingTimer;
private void InitializeAndStartSlidingTimer()
{
    if (slidingTimer == null)
    {
        slidingTimer = new SlidingTimer(IdleTimeInMilliSecondsRequiredToProcessEvent);
        App.Current.MainWindow.LocationChanged += MainWindow_LocationChanged;
        slidingTimer.Tick += (sender, args) =>
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {

                string loc = $"{App.Current.MainWindow.Left},{App.Current.MainWindow.Top}";
                this.LocationTextBlock.Text = loc;
                Console.WriteLine(loc);
            }));
        };
    }
}
private void MainWindow_LocationChanged(object sender, EventArgs e)
{
    Console.WriteLine("Event fired restart sliding timer");
    slidingTimer.StartOrRestart();
}
The above code can be in any WPF UI component's code behind file. Prerequisite is to have a TextBlock called LocationTextBlock in the UI class. InitializeAndStartSlidingTimer() can be called in the beginning or at any suitable time to initialize the SlidingTimer. Since the Window.LocationChanged is subscribed after initialization, its fine here. Those can vary depends on our scenario. 

Here the SlidingTimer is initialized with an idle timeout which required to tick after it is started or restarted. In the MainWindow_LocationChanged event handler, the slidingTimer is restarted. If there is no StartOrRestart() called continuously for 2000 milliseconds, the Tick event will fire. The Tick event handler uses dispatcher to manipulate the UI as the event fires in different thread.

Now lets see how the SlidingTimer class looks like
internal sealed class SlidingTimer
{
    Timer _internalTimer;

    private void OnTick(EventArgs args)
    {
        if(Tick !=null)
        {
            Tick(this, args);
        }
    }
    /// <summary>
    /// Fires in separate thread, when the there is enough delay to execute task.
    /// </summary>
    public event EventHandler Tick;
    int _intervalInMilliSeconds;
    public SlidingTimer(int intervalInMilliSeconds)
    {
        _intervalInMilliSeconds = intervalInMilliSeconds;
        _internalTimer = new Timer((state) =>
        {
            OnTick(EventArgs.Empty);
        });
    }
    internal void StartOrRestart()
    {
        _internalTimer.Change(_intervalInMilliSeconds, Timeout.Infinite);
    }
}
Here a thread timer is used for timing purpose. After it is started, the invocation of the callback event handler is controlled by the StartOrRestart(). Suppose the interval is 2 seconds, if internal timer starts and the StartorRestart() called after 1 seconds the total time slides to 3 seconds to get the event fired. This is simple sliding mechanism.

Monitoring timer 

The original use case can be done by using a normal timer as well. The event handler can just set a flag to indicate the processing is required. When the timer ticks it can check the flag and do the operation. After timer operation it needs to reset the flag.

Happy coding.

1 comment:

Blogger said...

Are you looking to earn cash from your visitors by popunder advertisments?
If so, have you ever used PropellerAds?