2012-03-22 248 views
2

我的应用程序严重依赖线程来处理超大型数据的复杂处理。随着处理完成,UI需要更新。我知道并尝试使用BackgroundWorker'sOnProgressChangedRunWorkerCompleted方法来更新UI。还使用UI线程的Invoke方法进行更新。在Win XP 32位和64位操作系统上似乎一切正常。在Win Vista和Win 7(32和64位)上,通过使用Invoke方法更新UI时,应用程序会随机挂起。从C#中的线程更新UI的其他方法

Invoke的行为在不同的Win OS上有变化吗? 除Invoke之外,还有哪些更新线程的UI的方法?

感谢

+0

我的假设是,在不同的操作系统和环境中,更新UI只是需要更长的时间。 – RQDQ 2012-03-22 15:21:36

+1

我不认为这个问题是新的操作系统 - 我的猜测是,新机器只是更快/有更多的核心(所以并发问题可能会更早到达),或者你只是幸运 - 无论如何:没有代码我不' t认为我们可以帮你 – Carsten 2012-03-22 15:21:52

+1

应用程序不响应,或不刷新本身? – 2012-03-22 15:30:30

回答

2

Invoke的行为在不同的Win OS上有变化吗?

它应该不,不。但是,线程问题可能以非常不可预测的方式实现。有可能你有一个未知的问题。

除了Invoke之外,从线程更新UI的其他方法是什么?

使用InvokeBeginInvoke被过度使用,特别是在尝试向UI线程报告简单进度信息时。如果您搜索一些与该主题相关的答案,您将会看到我一直在使用这种方法。并且有很好的理由,因为它们使用这种技术有很多缺点。不幸的是,BackgroundWorker仅通过其ProgressChanged事件使用此机制来更新UI。

另一种方法是让您的工作线程将进度信息发布到共享变量中,并让UI线程通过定时器定期轮询它。以下是我通常谈论的一些关于通过编组技术证明这种方法的论点。

  • InvokeBeginInvoke是昂贵的操作。
  • UI线程可以决定更新表单及其控件的时间和频率。
  • 它消除了UI和工作线程之间的紧密耦合,这些线程与ISynchronizeInvoke强加。
  • 使用一堆编组操作,没有超出UI或使UI消息队列饱和的风险。
  • 您可以在工作线程上获得更多吞吐量,因为它不必等待响应,就像Invoke那样。
+0

我可以保证这种方法。我已经编写了一个应用程序,每秒接收100次更新。 (通过中间件)尝试显示每个人和每个人都是荒谬的,所以我使用上面概述的方法。结果是一个更有用的用户界面。 – Fen 2012-03-22 16:26:28

1

你可以尝试使用Invoke()或的BeginInvoke()重载需要Dispatcher.Priority枚举作为参数之一。如果您选择了诸如“背景”之类的参数,您应该会看到您的应用程序仍然响应。唯一的问题就是确保您在不增加队列的情况下以适当的速率为您的传入数据提供服务。

2

不确定发生了什么问题,但您可以始终运行一个可以定期更新GUI的System.Windows.Forms.Timer;使用一些成员变量在线程之间传递原始数据,如果需要的话锁定内部。不是最优雅的解决方案,但它可能会给你一个不同的看法,因为线程更加独立,而不是依赖于主线程的后台线程。

+1

+1:相反...轮询进度信息往往*更优雅。 – 2012-03-22 16:01:33

0

另一种选择是完全放弃多线程。如果您的长时间运行可以分解为块,请在GUI线程中执行此操作,并在要更新GUI时使用Application.DoEvents()

我以前不喜欢使用该方法,因为它不仅可以更新GUI,还可以开始响应用户输入,启动定时器等,但最终它不会比使用后台线程安全, GUI随时开始做任何事情。所以可能在每次拨打Application.DoEvents()后,您需要检查_canceled或其他什么。 (我最终决定不喜欢这种方法的存在,因为它消除了线性执行顺序的保证,而不是使用它)。

当然,你会失去多核支持,所以如果你想同时运行大量的后台操作,它会影响性能。