Determine what is blocking UI thread

2020-06-03 05:02发布

问题:

I am working on a rather large .NET WPF real-time application. The application is working great and as expected, except for one BIG issue - UI Update is slow.

This application is highly event driven, there are events raised all over for all sorts of things - through these events the UI is updated.

One or many of these events is blocking the UI from displaying immediately. When all the work is complete, the UI shows the expected results.

Is there any way of determining which event handler is causing the bottleneck?

Any help would be appreciated.

回答1:

I fully support colithium's suggestion of using a profiler.

In addition, if the blocking takes more than a second, you might be able to hit the "Pause" button in Visual Studio. In the tool bar, there's a dropdown list where you can choose the "Main Thread". Then it jumps to the method which is currently blocking the UI.



回答2:

  public class UIBlockDetector
{
    static Timer _timer;
    public UIBlockDetector(int  maxFreezeTimeInMilliseconds = 200)
    {
        var sw = new Stopwatch();

        new DispatcherTimer(TimeSpan.FromMilliseconds(10), DispatcherPriority.Send, (sender, args) =>
        {
            lock (sw)
            {
                sw.Restart();
            }

        }, Application.Current.Dispatcher);

        _timer = new Timer(state =>
        {
            lock (sw)
            {
                if (sw.ElapsedMilliseconds > maxFreezeTimeInMilliseconds)
                {
                    // Debugger.Break() or set breakpoint here;
                    // Goto Visual Studio --> Debug --> Windows --> Theads 
                    // and checkup where the MainThread is.
                }
            }

        }, null, TimeSpan.FromMilliseconds(0), TimeSpan.FromMilliseconds(10));

    }

}

Just new this class in MainWindow constructor. When the breakpoint hits, you can go to Visual Studio --> Debug --> Windows --> Threads and check what operation blocked your UI-Thread!



回答3:

Do you have access to a code profiler? This is the type of thing they are good at. I recommend obtaining one if the answer is no.

Besides using a profiler. You can do "poor man's" profiling by placing timing statements at the beginning and end of code blocks that you suspect. You can even use a breakpoints and time it with a wall clock. Does the issue happen when you click something? If so start there. Is it a recurring issue without user interaction? Start with timers then.

As for actually solving the problem... Unless the offending handler is doing something that can be made more efficient, consider adopting a multi-threaded approach. The new Task library for .NET 4.0 is really amazing in this regard.



回答4:

As a first order approxximation, I find it useful to break in the debugger (with the pause button in the IDE), and look at the stack. Do this a few times, and you can see if there is a pattern. Are you always in the same function? Are you doing something expensive in response to an event? Are you getting more events that you expect? It's low tech, but can be very effective.