2012-03-16 201 views
1

这里的问题有点抽象。我们都知道,为后台线程更新一些UI元素。从多个后台线程更新UI

Dispatcher.Invoke() 

是唯一的选择(是吗?)。但是,Dispatcher.Invoke()本身将更新任务委托给UI线程。考虑以下场景:

  • 后台线程经常更新UI。
  • 数十个线程更新相同的用户界面。

Dispatcher对象会继续将更新任务委托给UI线程,并且UI线程可能会变慢。什么是可能的解决方案?我们如何解决Windows Forms中的这个问题,其中线程模型与WPF非常相似? WPF是否提供了其他线程技术?

问候,

回答

1

首先为什么需要更新频繁出现人眼不会注意到的UI,理想情况下,即使任何进度更新了一秒钟的间隔,也是可以接受的。例如,如果您正在编写一个文件,并且您可能每30毫秒写入4K字节,人眼就不会注意到,我们也不会在乎屏幕上的性能(以毫秒为单位)

不仅您将使UI线程忙,而且分派器。调用也会阻塞你的其他线程直到执行完成后,Dispatcher.BeginInvoke将不会阻塞您的其他线程。

如果UI线程只是在屏幕上更新少量标签或进度,它可能会在几毫秒内完成更新。

WPF和任何其他平台都不能提供任何更好的方式,因为UI非常复杂,并且允许从多个线程访问可能导致死锁,因此应用程序可能会变得无法响应。这就是每个平台的原因,无论是java,objective-c还是任何UI框架,都需要您仅在UI的创建者线程中更新UI。

但是,WPF中还有一种方法可以在每个窗口中创建多个UI线程,但它也相当复杂。游戏等使用了一种称为双缓冲的东西,在后台使用单独的线程处理一个缓冲区,而前一个缓冲区仍在屏幕上更新。

+0

感谢您的回复。 “但是,WPF中也有一种方法可以在每个窗口中创建多个UI线程,但它也相当复杂。”我了解所提供的所有风险,这可能是我正在寻找的解决方案。 我从http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/ 开始您可以发布一个更好的链接来开始使用这个概念吗? 谢谢。 :) – James 2012-03-16 10:48:47

2

如果您通过发布消息,超载的GUI线程输入队列(APC的,代表,等等),速度比他们可以处理,那么就会出现问题,不管WPF /表格/不管。

在那些情况下,其中多个GUI状态被如此频繁更新的发布的每一个变化都会超载队列和/或导致改变太快是人类可读的显示器,是很常见的非GUI线程存储他们在共享对象中的最新数据以及GUI线程以更合理的间隔使用定时器显示数据。

如果所有数据必须在不损失的情况下显示的,(例如,一个GUI备忘录或HTML呈现器必须显示发送的所有内容)经由对象池和/或数据的懒惰张贴,则合适的流程控制,可能需要防止消息队列超载。

'这里的问题有点抽象' - 不是那么抽象。我在忙碌的应用程序中多次遇到此问题。在我的东西中,长时间的输入队列过载往往会导致死锁,因为我的线程间通信池中的所有对象都卡在张贴的消息中,因为GUI被阻塞而无法处理并释放到池中 - 尝试获取对象从空池开始:((

+0

其实,你应该用Invoke确定。它的BeginInvoke往往阻塞队列。 – 2012-03-16 10:20:25

1

简单,不要使用Invoke来更新UI。相反,让工作线程将需要“发送到UI线程”的数据发布到像队列或列表这样的共享数据结构中,并让UI线程在特定时间间隔内进行轮询。这有几个优点。

  • 它打破了Invoke强加的UI和工作线程之间的紧密耦合。
  • 用户界面线程可以在UI控件更新时指示它......当你真的想到它时应该这样做。
  • 如果在工作线程中使用InvokeBeginInvoke,则不会有超出UI消息队列或消除其他消息的风险。
  • 工作线程不必等待来自UI线程的响应,就像Invoke那样。
  • 您可以在UI和工作线程上获得更高的吞吐量。
  • InvokeBeginInvoke是昂贵的操作。

我知道我一直在关注这个,但在很多情况下,Invoke真的有更好的选择。诸如Invoke之类的编组技术是方式过度使用。