确定什么是阻止UI线程

时间:2021-04-04 20:57:59

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.

我正在开发一个相当大的.NET WPF实时应用程序。该应用程序运行良好,正如预期的那样,除了一个大问题 - UI更新很慢。

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

这个应用程序是高度事件驱动的,有各种各样的事件引发 - 通过这些事件UI更新。

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.

这些事件中的一个或多个阻止UI立即显示。完成所有工作后,UI会显示预期结果。

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

有没有办法确定哪个事件处理程序导致瓶颈?

Any help would be appreciated.

任何帮助,将不胜感激。

4 个解决方案

#1


8  

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

我完全支持colithium建议使用分析器。

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.

此外,如果阻塞花费的时间超过一秒,您可以在Visual Studio中点击“暂停”按钮。在工具栏中,有一个下拉列表,您可以在其中选择“主线程”。然后它跳转到当前阻止UI的方法。

#2


10  

  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!

在MainWindow构造函数中新建这个类。当断点命中时,您可以转到Visual Studio - > Debug - > Windows - > Threads并检查哪些操作阻止了您的UI-Thread!

#3


5  

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.

至于实际解决问题...除非违规处理程序正在做一些可以提高效率的事情,否则考虑采用多线程方法。在这方面,.NET 4.0的新任务库真的很棒。

#4


1  

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.

作为一阶近似,我发现打破调试器(使用IDE中的暂停按钮)很有用,并查看堆栈。这样做几次,你可以看看是否有模式。你总是在同一个职能部门吗?您是否正在为活动做些昂贵的事情?您是否收到了更多您期望的活动?这是低技术,但可以非常有效。

#1


8  

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

我完全支持colithium建议使用分析器。

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.

此外,如果阻塞花费的时间超过一秒,您可以在Visual Studio中点击“暂停”按钮。在工具栏中,有一个下拉列表,您可以在其中选择“主线程”。然后它跳转到当前阻止UI的方法。

#2


10  

  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!

在MainWindow构造函数中新建这个类。当断点命中时,您可以转到Visual Studio - > Debug - > Windows - > Threads并检查哪些操作阻止了您的UI-Thread!

#3


5  

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.

至于实际解决问题...除非违规处理程序正在做一些可以提高效率的事情,否则考虑采用多线程方法。在这方面,.NET 4.0的新任务库真的很棒。

#4


1  

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.

作为一阶近似,我发现打破调试器(使用IDE中的暂停按钮)很有用,并查看堆栈。这样做几次,你可以看看是否有模式。你总是在同一个职能部门吗?您是否正在为活动做些昂贵的事情?您是否收到了更多您期望的活动?这是低技术,但可以非常有效。