Timer.Elapsed and BeginInvoke still lag GUI

677 views Asked by At

There is a piece of 3rd party API code, SomeWork(), that needs to run every 3 seconds to monitor some physical devices. I would of thought using using System.Timers.Timer and its Elapse event is asynchronous, but it lags my GUI operation every 3 seconds. I tried doing SomeWork() using Dispatcher.BeginInvoke yet I still experience the same lag on the GUI, even SomeWork() does not actually update any GUI and should not occupy the GUI thread.

private void StartTimerAtStartup()
{
    System.Timers.Timer connTimer = new System.Timers.Timer();
    connTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);
    connTimer.Interval = 3000; 
    connTimer.Enabled = true;
}

private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)
{
    if (!Dispatcher.CheckAccess())
    {
        Dispatcher.BeginInvoke(DispatcherPriority.Send, (ElapsedEventHandler)MyTimer_Elapsed, sender, e);
        return;
    }

    // Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(
    //             () => SomeWork())
    // );

    SomeWork();
}

[EDIT1]

If I remove all Dispatcher and call SomeWork() directly then I get an exception that I cannot access this thread.

[EDIT2]

SomeWork() is a 3rd party API listening to physical devices and receiving packets, which does not touch the GUI. I tried various ways of doing the Dispatcher.BeginInvoke and I encounter the following, which I cannot understand. Why would using lamda lags the GUI but doing a delegate does not lag the GUI?

// This lags the GUI
Dispatcher.BeginInvoke(new Action( () => SomeWork() ));

// This does not lag the GUI. Application runs smooth, 
// but I do not understand why
Dispatcher.BeginInvoke((Action)delegate () { SomeWork(); });
1

There are 1 answers

0
Yuriy Tseretyan On BEST ANSWER

You call Dispatcher of GUI thread. Thus, BeginInvoke invokes async work to UI thread and you get your UI lagged. Your timer fires Elapsed event in the different than UI thread. So you can just simply call your method in the event handler.

However, if you need to call your API strictly every 3 seconds than you need to either consider time that takes to execute SomeWork or do the job in separated thread. Then you can use tasks to achieve that.

 Task.Factory.StartNew(SomeWork);

But in this case you will have to deal with possible race conditions and synchronize your work.