Problem with WPF Application and slow GUI response - wpf

I've been analyzing a WPF application which basically fetch data from a server and display the data in the GUI.
This code is not mine, and the application has a problem related with slow response from the GUI, I'm trying to find the reason for that problem.
I want to share with you my idea of which the problem could be and I'll like to hear what do you think about it, whether it makes any sense or not.
To get the data from the server, the application is using 7 threads (this is done in this way mostly because of the application logic, so don't pay too much attention to why 7 and not just one...), now, each thread is created by calling a method, called CreateThreadForTask()
public void StartAllThreads()
{
this.CreateThreadForTask(Tasks.Task1);
this.CreateThreadForTask(Tasks.Task2);
this.CreateThreadForTask(Tasks.Task3);
this.CreateThreadForTask(Tasks.Task4);
this.CreateThreadForTask(Tasks.Task5);
this.CreateThreadForTask(Tasks.Task6);
this.CreateThreadForTask(Tasks.Task7);
}
public void CreateThreadForTask(Tasks task)
{
... // this part of the code is not important
//! Initialize and start timer
timer = null;
timer = new DispatcherTimer();
timer.Tick += new EventHandler(RunMainSyncForTask);
timer.Start();
}
public void RunMainSyncForTask(object s, EventArgs e)
{
int sec = int.Parse(AppSettings.GetSetting("syncInterval"));
timer.Interval = new TimeSpan(0, 0, sec);
//threadCaller is a background worker
threadCaller = InitializeThread();
threadCaller.DoWork += DoWorkEventHandler(StartSync);
threadCaller.RunWorkerAsync();
}
When I was debugging the code I noticed that all the threads are created using a DispatcherTimer; what I think is that the application is creating 7 DispatcherTimer's and is linking the Tick event of the timers with the RunMainSyncForTask() method, which inside, create a background worker that fetch the data from the server and save that data to a local database.
Now, this was taken from the MSDN
The DispatcherTimer is reevaluated at the top of every Dispatcher loop.
Timers are not guaranteed to execute exactly when the time interval occurs, but they are guaranteed to not execute before the time interval occurs. This is because DispatcherTimer operations are placed on the Dispatcher queue like other operations. When the DispatcherTimer operation executes is dependent on the other jobs in the queue and their priorities.
So, based on that I believe that the application is spamming threads every time a timer does a tick event, and this is done 7 times simultaneously; and all these operations, because of the DispatcherTimer nature, are being added to the Dispatcher queue, which makes the GUI response slow, due to the Dispatcher being busy.
Also, another problem with the application is that, when it runs, it takes about 90-95% of the CPU, I think that if my hypothesis is right, this could be also the cause of for this problem.
So if you can share some insides about this I'll appreciate it.
Thanks.

You're getting the 90-95% CPU because you've instituted a form of busy waiting through a crazy web of threading calls.
If you're using this StartSync logic to post status notifications or get data back to the GUI, you're jumping through a lot of hoops. If you're on .Net 4.0 you should switch to the Task Parallel Library and let the framework handle all of this for you. It also supports graceful cancellation, etc.
If you don't wish to use TPL, I would suggest instead passing the Windows Dispatcher (use the usual suspects: Invoke or BeginInvoke) or SynchronizationContext (asynchronously with Post, synchronously with Send) to the individual tasks for use for these tasks which must be done in the GUI.

Related

How to tell Dispatcher is initialized and running?

In my console app I've been trying to start an STA thread and show a WPF window. I've succeeded showing the window, but I had issues with a library using Dispatcher (System.Reactive.Windows.Threading to be precised). I've fixed my problems using code from this doc - what I was missing was calling System.Windows.Threading.Dispatcher.Run() in the right moment.
But after reading this article carefully (and others) and examining Dispatcher's API I still don't know: how to tell WPF Dispatcher is correctly initialized and running? It'd be very useful for libraries requiring Dispatcher, if they could check it.
-- EDIT --
// Extending my question after #Peter Duniho remarks
Having C# console application I wanted to create a WPF window, where I'll observe, on Dispatcher, some data. The full code is here
So I have my program, where Main class looks like that:
static void Main(string[] args)
{
var observable = Observable
.Interval(TimeSpan.FromMilliseconds(500))
.TakeWhile(counter => counter < 10);
var thread = new Thread(() =>
{
new TestWindow(observable);
Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
Console.ReadKey();
}
I create here an observable with Interval operator, which ticks every 500 milliseconds, and I pass it to a TestWindow (code below) which I run on a separate thread. After 10 ticks I end the observable sequence.
TestWindow class:
public class TestWindow : Window
{
public TestWindow(IObservable<long> observable)
{
var isDispatcherInitialized = false;
Dispatcher.Invoke(() => isDispatcherInitialized = true, DispatcherPriority.ApplicationIdle);
if (!isDispatcherInitialized)
throw new ApplicationException("Dispatcher not initialized");
observable
.ObserveOnDispatcher()
.Window(TimeSpan.FromMilliseconds(600))
.Subscribe(_ => Console.WriteLine($"OnNext, observed on dispatcher with Window operator"));
}
}
In TestWindow I observe my observable on Dispatcher (ObserveOnDispatcher()), and I use Window operator.
PROBLEM with that code (tested on .NET Framework and on .NET Core 3.0 preview):
if I don't call Dispatcher.Run(); when starting STA thread, the validation where I call Dispatcher.Invoke() will be passed, but ObserveOnDispatcher() won't work correctly - subscription never stops, and the message: "OnNext, observed on dispatcher with Window operator" goes forever.
That's why I was wondering if I could detect Dispatcher's state.
It would be helpful if you would elaborate on this statement:
It'd be very useful for libraries requiring Dispatcher, if they could check it.
That is, why would it be useful?
For one, if you are using a third-party library (such as the Reactive Extensions (Rx) for .NET you mentioned, how would you knowing how to check for the dispatcher state help that library?
For another, what scenario doesn't work for you? Lacking a specific problem to solve, your question is fairly open-ended. It's not clear what type of answer would actually address your question.
That said, two things come to mind:
If you want to know if a dispatcher has been created for a given thread, you should call System.Windows.Threading.Dispatcher.FromThread(System.Threading.Thread.CurrentThread); This will return null if not dispatcher has been created yet for that thread, or a reference to the dispatcher if it has been.
If you want to know that the dispatcher has completed initialization and is ready to dispatch things, it seems to me that the easiest thing to do is ask it to dispatch something, and when it does, it's ready. Using an overload of one of the invoking methods (BeginInvoke(), Invoke(), or InvokeAsync()) that takes a DispatcherPriority value, you can get fine-grained information regarding just what level of initialization has happened. For example, if you pass DispatcherPriority.Normal or DispatcherPriority.Send, when your delegate is invoked you'll know that the dispatcher is running. But if you pass DispatcherPriority.ApplicationIdle or DispatcherPriority.SystemIdle, you'll know that not only is the dispatcher running, but it's cleared its backlog of initial events to dispatch and the application is sitting waiting for user input.

With WPF, is there a method to detect method calls that are blocking GUI updates?

I'm wondering if there is some technique or method to detect calls in a WPF app that are not using async/await.
The reason I ask is that the WPF app I am working on is stuttering and halting on the screen updates, and I can't seem to track down the source of the calls that are blocking the GUI thread.
I am using VS2012 and VS2013 with the MVVM design pattern.
This doesn't answer your question directly but this will help with identifying when the dispatcher thread is overloaded, the following code uses an event handler around the DispatcherInactive event to calculate how long dispatcher thread has been overloaded (blocked) with work:
var maxThreshold = TimeSpan.FromMilliseconds(750);
var previous = DateTime.Now;
Application.Current.MainWindow
.Dispatcher.Hooks.DispatcherInactive += (sender, eventArgs) =>
{
var current = DateTime.Now;
var delta = current - previous;
previous = current;
if (delta > maxThreshold)
{
Debug.WriteLine("UI Freeze = {0} ms", delta.TotalMilliseconds);
}
};
I would suggest this is only ever used in debug mode, so it would be wrapped in a #if DEBUG block. You don't want this running in production.
I think a performance profiler could help you in this case.
I personally recommend ANTS profiler, you can download a trial and test your application with it. It would tell you where a certain period of the execution of your app is spending its time in.
Usually it is very easy to find what is blocking the UI. There can be 2 cases - either you are performing an expensive operation on the UI thread, you can test if the thread executing is the UI thread using:
if (Thread.CurrentThread == Dispatcher.CurrentDispatcher.Thread)
{
//UI Thread
}
Or, you are displaying to many controls and it takes long time to render. Usually the lists cause this when the list is not virtualizing items.
You can subscribe to events of the WPF dispatcher to track down your problem. The UI thread queues work items inside an object called a Dispatcher. The Dispatcher selects work items on a priority basis and runs each one to completion.
To monitor the Dispatcher you can e.g. subscribe to these operations:
Dispatcher.Hooks.OperationPosted += Hooks_OperationPosted;
Dispatcher.Hooks.OperationStarted += Hooks_OperationStarted;
Dispatcher.Hooks.OperationAborted += Hooks_OperationAborted;
You find a full list here.
Depending on your problem you might find yourself better of with a commercial profiler but quite often you get good results with just observing the dispatcher queue.

Question about making Asynchronous call in C# (WPF) to COM object

Sorry to ask such a basic question but I seem to have a brain freeze on this one! I'm calling a COM (ATL) object from my WPF project. The COM method might take a long time to complete. I thought I'd try and call it asychronously. I have a few demo lines that show the problem.
private void checkBox1_Checked(object sender, RoutedEventArgs e)
{
//DoSomeWork();
AsyncDoWork caller = new AsyncDoWork(DoSomeWork);
IAsyncResult result = caller.BeginInvoke(null, null);
}
private delegate void AsyncDoWork();
private void DoSomeWork()
{
_Server.DoWork();
}
The ATL method DoWork is very exciting. It is:
STDMETHODIMP CSimpleObject::DoWork(void)
{
Sleep(5000);
return S_OK;
}
I had expectations that running this way would result in the checkbox being checked right away (instead of in 5 seconds) and me being able to move the WPF gui around the screen. I can't - for 5 seconds.
What am I doing wrong? I'm sure it's something pretty simple. Delegate signature wrong?
Thanks.
I'm sure you're right about the call to your ATL code getting marshaled to the GUI thread because the ATL code is STA, thereby blocking your GUI thread.
Two solutions:
Rearchitect the ATL portion to be MTA, which may not be feasible, or
Leave the ATL as STA but initially construct the COM object in a thread created for that purpose so it will get a different apartment.
A WPF application actually runs just fine with multiple UI threads, as long as each UI thread has manages its own part of the UI, and the parts are separated by HwndSource. In other words, the second thread that runs part of the UI implements a Win32 HWND which is then embedded in the portion of the UI run by the main thread.
If your COM object isn't itself a GUI object, then it should be very easy to construct it in a separate worker thread and leave it there. Since it is a STA object, all calls will be marshaled to the other thread.
BeginInvoke is still going to execute your call on the same thread, just asynchronously*. You can either create a new Thread object:
Thread comthread = new Thread(new ThreadStart(delegate() { DoSomeWork(); }));
comthread.Start();
or try out .Net 4's new Task library:
Task.Factory.StartNew(() =>
{
DoSomeWork();
});
which are essentially the same thing.**
*A delegate type's BeginInvoke method executes on the same thread as the caller, but in the background. I'm not sure if there are rules regarding what gets executed when, but it's certainly not in the order you want. However, asynchronous methods like BeginRead execute on a special thread separate from the main one.
**There is a slight difference - the Thread method will always create a new Thread object, whereas the Task system has a pool of threads to work with, which is in theory more efficient.
I have done some more thinking and testing about this. There is nothing wrong with the C# code. If the ATL object is an STA object (as it was in my case), it will be called on the main thread, regardless of attempts by the C# code to call it on a worker thread. Changing the ATL object to an MTA object makes it possible to to call it asynchronously.

Does using dispatcher.Invoke make my thread safe?

In my WPF app I have a long running upload running, which raises progress events as it goes which updates a progress bar. The user also has a chance of cancelling the upload, or it might go wrong. These are all async events, so they need to be executed using Dispatcher.Invoke in order to update the UI.
So the code looks like this, ish:
void OnCancelButtonClicked(object sender, EventArgs e)
{
upload.Cancel();
_cancelled = true;
view.Close();
view.Dispose();
}
void OnProgressReceived(object sender, EventArgs<double> e)
{
Dispatcher.Invoke(() =>
{
if (!cancelled)
view.Progress = e.Value;
}
}
Supposing that setting view.Progress on a disposed view is going to throw an error, is this code thread safe? i.e. if a user clicks cancel while the progress is updating, he/she will have to wait until the progress has been updated, and if the progress is updated during execution of OnCancelButtonClicked, the Dispatcher.Invoke call will cause the view.Progress update to be queued til after _cancelled is set, so I won't get a problem there.
Or do I need a lock to be safe, a la:
object myLock = new object();
void OnCancelButtonClicked(object sender, EventArgs e)
{
lock(myLock)
{
upload.Cancel();
_cancelled = true;
view.Close();
view.Dispose();
}
}
void OnProgressReceived(object sender, EventArgs<double> e)
{
Dispatcher.Invoke(() =>
{
lock(myLock)
{
if (!cancelled)
view.Progress = e.Value;
}
}
}
You don't have to add a lock. Dispatcher.Invoke and BeginInvoke requests will not run in the middle of other code (that's the whole point of them).
Just two things to consider:
BeginInvoke may be more appropriate in this case, Invoke will queue the request and then block the calling thread until the UI thread becomes idle and finishes executing the code, BeginInvoke will only queue the request without blocking.
Some operations, especially operations that open windows (including message boxes) or do inter-process communication may allow the queued dispatcher operations to run.
EDIT: first, I don't have citations because the MSDN pages on the subject are unfortunately very low on details - but I have written test programs to check the behavior of BeginInvoke and everything I write here is the result of those tests.
Now, to expand on the second point we first need to understand what the dispatcher does. Obviously this is a very simplified explanation.
Any Windows UI works by processing messages; For example when the user moves the mouse over a window the system will send that window a WM_MOUSEMOVE message.
The system send the message by adding it a queue, each thread may have a queue, all windows created by the same thread share the same queue.
In the heart of every Windows program there's a loop called "message loop" or "message pump", this loop reads the next message from the queue and calls the appropriate window's code to process that message.
In WPF this loop and all the related processing handled by the Dispatcher.
An application can either be in the message loop waiting for the next message or it could be doing something. That is why when you have a long calculation all the thread's windows become unresponsive - the thread is busy working and doesn't return to the message loop to process the next message.
Dispatcher.Invoke and BeginInvoke works by queuing the requested operation and executing it the next time the thread returns to the message loop.
That is why Dispatcher.(Begin)Invoke can't "inject" code in the middle of your method, you won't get back to the message loop until your method returns.
BUT
Any code can run a message loop. When you call anything that runs a message loop the Dispatcher will be called and can run the (Begin)Invoke operations.
What kinds of code has a message loop?
Anything that has a GUI or that accepts user input, for example dialog boxes, message boxes, drag&drop etc. - if those didn't have a message loop then the app would have been unresponsive and unable to handle user input.
Inter-process communication that uses windows messages behind the scenes (most inter-process communication methods, including COM, use them).
Anything else that takes a long time and doesn't freeze the system (the fast that the system isn't frozen is proof it's processing messages).
So, to summarize:
the Dispatcher can't just drop code into your thread, it can only execute code when the application is in the "message loop".
Any code you write doesn't have message loops unless you explicitly wrote them.
Most UI code doesn't have it's own message loop, for example if you call Window.Show and then do some long calculation the window will only appear after the calculation is finished and the method returns (and the app returns to the message loop and processes all the messages required to open and draw a window).
But any code that interacts with the user before it returns (MessageBox.Show, Window.ShowDialog) has to have a message loop.
Some communication code (network and inter-process) uses message loops, some doesn't, depending on the specific implementation you are using.
This is an interesting question. Items executed in the dispatcher are queued and execute on the same thread as UI interaction. Here's the best article on this subject:
http://msdn.microsoft.com/en-us/library/ms741870.aspx
If I were to venture a guess, I would say that Dispatcher.Invoke(Action) probably queues an atomic work item, so it's likely going to be ok, however I'm not sure if it wraps up your UI event handler in an atomic action item for instance:
//Are these bits atomic? Not sure.
upload.Cancel();
_cancelled = true;
For safety's sake I would personally lock, but your question warrants more research. Might need a dive in reflector to figure out for sure.
As an aside, I'd probably optimize your lock a bit.
Dispatcher.Invoke(() =>
{
if (!cancelled)
{
lock(myLock)
{
if(!cancelled)
view.Progress = e.Value;
}
}
}
But that's probably overkill :)

Prevent UI from freezing without additional threads

What solutions do I have if I want to prevent the UI from freezing while I deserialize a large number of UI elements in WPF? I'm getting errors complainig that the objects belong on the UI Thread when I'm trying to load them in another thread. So, what options do I have to prevent the Vista "Program not responding" error while I'm loading my UI data? Can I rely on a single-threaded solution, or am I missing something regarding perhaps multiple UI Threads?
If you only use a single thread then the UI will freeze while you do any amount of processing.
If you use a BackgroundWorker thread you'll have more control over what happens & when.
To update the UI you need to use Dispatcher.Invoke from your background thread to marshal the call across the thread boundary.
Dispatcher.Invoke(DispatcherPriority.Background,
new Action(() => this.TextBlock.Text = "Processing");
You can turn the flow of control on its head using DispatcherFrames, allowing a deserialization to proceed on the UI thread in the background.
First you need a way to get control periodically during deserialization. No matter what deserializer you are using, it will have to call property sets on your objects, so you can usually add code to the property setters. Alternatively you could modify the deserializer. In any case, make sure your code is called frequently enough
Each time you receive control, all you need to do is:
Create a DispatcherFrame
Queue an event to the dispatcher using BeginInvoke that sets Continue=false on the frame
Use PushFrame to start the frame running on the Dispatcher
In addition, when calling the deserializer itself make sure you do it from Dispatcher.BeginInvoke, or that your calling code doesn't hold any locks etc.
Here's how it would look:
public partial class MyWindow
{
SomeDeserializer _deserializer = new SomeDeserializer();
byte[] _sourceData;
object _deserializedObject;
...
void LoadButton_Click(...)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
_deserializedObject = _deserializer.DeserializeObject(_sourceData);
}));
}
}
public class OneOfTheObjectsBeingDeserializedFrequently
{
...
public string SomePropertyThatIsFrequentlySet
{
get { ... }
set { ...; BackgroundThreadingSolution.DoEvents(); }
}
}
public class BackgroundThreadingSolution
{
[ThreadLocal]
static DateTime _nextDispatchTime;
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
frame.Continue = false;
}));
Dispatcher.PushFrame(frame);
}
}
Checking DateTime.Now in DoEvents() isn't actually required for this technique to work, but will improve performance if SomeProperty is set very frequently during deserialization.
Edit: Right after I wrote this I realized there is an easier way to implement the DoEvents method. Instead of using DispatcherFrame, simply use Dispatcher.Invoke with an empty action:
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => {}));
}
Here is a wonderful blog posting from Dwane Need that discusses all the available options for working with UI elements amongst multiple threads.
You really haven't given enough detail to give a good prescription. For example, why are you creating UI elements yourself at all instead of using databinding? You might have a good reason, but without more details it's hard to give good advice. As another example of detail that would be useful, are you looking to build complex deeply nested control hierarchies for each piece of data or do you just need to draw a simple shape?
I had a similar problem with my panel which was moving its items. The UI was freezing because I was using a DispatcherTimer at priority Loaded. The problem is gone as soon as I changed it to DispatcherPriority.Input.
You can still make your long processing in a separate thread, but when finished you have to synchronize with the UI thread by calling Dispatcher.BeginInvoke(your_UI_action_here)
Recommendations from the OldNewThing blog.
It is best if you do go the threaded route, to have one GUI thread and spawn your work load off to another thread that when finishes reports back to the main GUI thread that its done. The reason for this is because you will not get into thread issues with your GUI interface.
So One GUI Thread
Many worker threads that do the work.
If any of your threads do hang the user is in direct control over your application can can close down the thread without effecting his experience with the application interface. This will make him happy because your user will feel in control other than him constantly click THAT STOP BUTTON AND IT WONT STOP SEARCHING.
Try freezing your UIElements. Frozen objects can be passed between threads without encountering an InvalidOperationException, so you deserialize them & freeze them on a background thread before using them on your UI thread.
Alternatively, consider dispatching the individual deserializations back to the UI thread at background priority. This isn't optimal, since the UI thread still has to do all of the work to deserialize these objects and there's some overhead added by dispatching them as individual tasks, but at least you won't block the UI - higher priority events like input will be able to be interspersed with your lower priority deserialization work.

Resources