WPF应用程序存在问题,GUI响应缓慢。

4
我一直在分析一个 WPF 应用程序,基本上是从服务器获取数据并在 GUI 中显示数据。
这段代码不是我的,应用程序存在与 GUI 响应慢有关的问题,我正在努力找出问题的原因。
我想与您分享我的想法,即可能存在的问题,并希望听听您对此的看法,无论它是否有意义。
为了从服务器获取数据,该应用程序使用了 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个DispatcherTimers,并将定时器的Tick事件与RunMainSyncForTask()方法链接起来,该方法内部创建了一个后台工作程序,从服务器获取数据并将该数据保存到本地数据库。
现在,这是从MSDN中获取的。
DispatcherTimer在每个Dispatcher循环顶部重新评估。
不能保证计时器恰好在时间间隔发生时执行,但可以保证它们不会在时间间隔之前执行。这是因为DispatcherTimer操作与其他操作一样放置在Dispatcher队列上。当DispatcherTimer操作执行取决于队列中的其他作业及其优先级。
所以,基于此,我认为每次定时器触发事件时,该应用程序都会同时产生大量线程;而且由于DispatcherTimer的特性,所有这些操作都被添加到Dispatcher队列中,这使得GUI响应变慢,因为Dispatcher很忙。
此外,该应用程序的另一个问题是,在运行时,它占用了大约90-95%的CPU。我认为如果我的假设是正确的,那么也可能会导致这个问题。
因此,如果您能分享一些有关此方面的见解,我将不胜感激。
谢谢。

你是在尝试将数据传回GUI吗?试图确定与主线程的“同步”原因。 - user7116
不,这些线程仅将数据下载到本地数据库,应用程序使用另外的线程每 X 秒更新 GUI。 - Vic
1个回答

1

你的CPU占用率达到了90-95%,因为你通过一系列繁琐的线程调用实现了一种忙等待形式。

如果你正在使用这个StartSync逻辑来发布状态通知或将数据返回给GUI,那么你需要跳过很多障碍。如果你在.Net 4.0上,应该切换到Task Parallel Library,让框架为你处理所有这些问题。它还支持优雅的取消等功能。

如果你不想使用TPL,我建议你传递WindowDispatcher(使用常规方法:Invoke或BeginInvoke)或SynchronizationContext(异步使用Post,同步使用Send)给各个任务,以便在GUI中完成这些任务。


感谢您的答案,StartSync是从服务器下载信息到本地数据库的方法,这个方法更新的唯一GUI部分是一个进度条,并且使用Dispatcher.Invoke()完成。但在几乎所有其他控制器上,GUI都很慢。现在,由于它是使用DispatcherTimer创建的,您不认为这可能会向Dispatcher队列添加任务,从而使GUI变慢吗?顺便说一句,该应用程序正在使用.Net 3.5。 - Vic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接