WPF应用程序问题和GUI响应缓慢

时间:2011-03-17 22:26:18

标签: wpf multithreading user-interface dispatcher dispatchertimer

我一直在分析一个WPF应用程序,它基本上从服务器获取数据并在GUI中显示数据。

此代码不是我的,并且应用程序存在与GUI响应缓慢相关的问题,我正试图找到导致该问题的原因。

我想与你分享我对这个问题的看法,我想听听你对它的看法,是否有意义。

要从服务器获取数据,应用程序使用7个线程(这样做主要是因为应用程序逻辑,所以不要过多关注为什么7而不只是一个......)现在,每个线程都是通过调用一个名为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();
}

当我调试代码时,我注意到所有线程都是使用DispatcherTimer创建的;我认为应用程序正在创建7个DispatcherTimer,并将定时器的Tick事件与RunMainSyncForTask()方法链接在一起,里面创建一个后台工作程序,从服务器获取数据并将该数据保存到本地数据库。

现在,这是从MSDN中获取的

  

DispatcherTimer在每个Dispatcher循环的顶部重新评估。

     

不保证定时器在时间间隔发生时准确执行,但保证在时间间隔发生之前不执行定时器。这是因为DispatcherTimer操作与其他操作一样放在Dispatcher队列中。 DispatcherTimer操作执行时依赖于队列中的其他作业及其优先级。

因此,基于此我认为应用程序每次定时器执行tick事件时都会发送垃圾邮件,并且同时执行7次;由于DispatcherTimer的性质,所有这些操作都被添加到Dispatcher队列中,由于Dispatcher忙,因此GUI响应变慢。

此外,该应用程序的另一个问题是,当它运行时,它占用了大约90-95%的CPU,我认为如果我的假设是正确的,这也可能是造成这个问题的原因。

所以,如果你可以分享一些内容,我会很感激。

感谢。

1 个答案:

答案 0 :(得分:1)

你获得了90-95%的CPU,因为你已经设置了一种繁忙的等待通过一个疯狂的线程调用网络。

如果您使用此StartSync逻辑发布状态通知或将数据返回到GUI,那么您就会遇到很多困难。如果你在.Net 4.0上,你应该切换到Task Parallel Library并让框架为你处理所有这些。它还支持优雅的取消等。

如果你不想使用TPL,我建议改为传递Window s Dispatcher(使用通常的嫌疑人:Invoke或BeginInvoke)或SynchronizationContext(与Post异步{1}},与Send同步,用于必须在GUI中完成的用于这些任务的各个任务。