2

我的应用程序严重依赖线程来执行非常大的数据的复杂处理。UI 需要在处理完成时更新。我知道并尝试使用BackgroundWorker's OnProgressChangedRunWorkerCompleted方法来更新 UI。也使用InvokeUI 线程的方法来更新。在 Win XP 32 位和 64 位操作系统上似乎一切正常。在 Win Vista 和 Win 7(32 位和 64 位)上,应用程序在使用Invoke方法更新 UI 时随机挂起。

Invoke不同 Win OS 上的行为是否会发生变化?除了从线程更新 UI 的其他方法是什么Invoke

谢谢

4

4 回答 4

2

不知道出了什么问题,但您总是可以System.Windows.Forms.Timer运行定期更新 GUI;使用一些成员变量在线程之间传递原始数据,必要时在锁内传递。不是最优雅的解决方案,但它可能会让您对挂起的内容有不同的看法,因为这样线程更加独立,而不是依赖于Invoke主线程的后台线程。

于 2012-03-22T15:34:33.193 回答
2

Invoke 的行为是否会在不同的 Win OS 上发生变化?

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

除了 Invoke,还有哪些其他从线程更新 UI 的方法?

使用InvokeorBeginInvoke被过度使用,尤其是在尝试向 UI 线程报告简单的进度信息时。如果您搜索我的一些与该主题相关的答案,您会发现我一直在使用这种方法。并且有充分的理由,因为它们对使用这种技术有很多缺点。不幸的是,BackgroundWorker这种机制专门用于通过其ProgressChanged事件更新 UI。

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

  • Invoke并且BeginInvoke是昂贵的操作。
  • UI 线程可以决定更新表单及其控件的时间和频率。
  • 它消除了 UI 和工作线程之间的紧密耦合ISynchronizeInvoke
  • 不存在使用一堆封送操作使 UI 消息队列溢出或饱和的风险。
  • 您可以在工作线程上获得更多吞吐量,因为它不必像Invoke.
于 2012-03-22T15:59:44.707 回答
1

您可以尝试使用将 Dispatcher.Priority 枚举作为参数的 Invoke() 或 BeginInvoke() 重载之一。如果您选择诸如“背景”之类的参数,您应该会看到您的应用程序仍然响应。唯一的问题是确保您以足够的速度为传入的数据提供服务,而不会增加队列。

于 2012-03-22T15:27:36.907 回答
0

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

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

当然,这样会失去多核支持,因此如果您尝试同时运行大量后台操作,则会影响性能。

于 2012-03-22T16:17:54.793 回答