假设我有一个WPF应用程序,我有以下架构:
[工作者主题] - > [队列1] - > [队列管理器线程] - > [队列2] - > [UI主题]
工作人员正在侦听来自某些服务的数据并在不确定的时间(可能是每秒多次或每几秒几次)接收该数据,然后将其排队到队列1,然后排队队列管理器,具体取决于“ UI线程的健康状况可能决定加快/减少数据项排队到队列2的速率,UI线程使用它来更新UI,可能会丢弃一些项目,以免压倒UI中的UI线程事件它接收太多消息(例如,如果消息之间的差异比UI更新自身的最后一个数据项至少早5秒,它可能会决定它将检查每个数据消息的时间戳并仅将其排入队列2 )
UI线程将有一个计时器,用于触发set-interval以使用来自Queue 2的新数据更新UI。我希望能够做的是确定UI更新自身以测量它的速度“响应性“为了节制,例如增加/减少关于更新UI的频率的计时器间隔
假设我的UI有很多控件(网格,图表等)都绑定到我的UI shell中队列2上数据的不同过滤/分组子集,并且UI在更新这些控件时开始变得无响应并在更新之间冻结,如何我可以从代码中检测到这一点,以便知道如何/何时增加/减少UI更新的间隔?基本上,我如何衡量在绑定到数据的所有控件上重新绑定整个UI所需的时间?
BTW这是一个很好的设计还是可以改进?我还有其他可以考虑的策略吗?答案 0 :(得分:4)
有2个主题...主要的UI线程......和渲染线程....您可能需要同时查看两者以确定应用程序的响应性......并决定如何限制。 / p>
您可以观看ETW事件,或者处理CompositionTarget.Rendering并自己计算帧....这是监视渲染线程...如果那是丢帧,那么它可以告诉您系统负担过重......你可以相应地限制你的背景工作。
http://blogs.msdn.com/b/jgoldb/archive/2008/09/26/etw-event-tracing-in-wpf.aspx
Why is Frame Rate in WPF Irregular and Not Limited To Monitor Refresh?
您可以使用@HenkHolterman提到的DispatcherTimer来监视UI线程上的负载,方法是让它以低于Normal的优先级运行,例如:背景....当在UI线程上处理/处理计时器事件时......然后你可以释放/告诉你的后台工作人员做下一项工作。
但是要小心......如果您的计时器间隔太小......并且您的系统过载......那么您可能会收到计时器消息的累积......所以当您的事件处理程序被调用时......你可能会做太多的工作(除非你保留上次调用它的记录)。
或者你可以让一个委托在特定优先级的UI线程上运行(例如通常是背景)。
如果您使用Dispatcher.BeginInvoke ....那么工作将被放入队列,并将在所有优先级较高的工作完成后执行。 (异步)。
如果您使用Dispatcher.Invoke ...那么您的线程将阻塞,直到您调用的Dispatcher中的所有更高优先级的工作完成,然后您的委托将执行。
(您的后台工作人员在完成其工作单元后会执行此操作,然后委托人会告诉您的后台工作人员执行下一个工作单元。)
这可能比DispatchTimer更好,因为你可以消除一些延迟...即。使用计时器的延迟取决于计时器间隔。
然后根据您找到的内容,您可以调整下一个工作单元。
如果你真的想要变得复杂,那么你可以从应用程序内部监控各种性能计数器,例如使用内存,GC集合等......并动态调整你的工作量。
答案 1 :(得分:2)
我只需删除QueueManager和Queue2。
您需要的只是一个WPF Dispatcher Timer(而不是Timers.Timer),它每隔几毫秒检查一次输入。您可以静态配置超时 然后使Queue1成为一个阻塞队列来限制上游的任何内容。
Dispatcher Timer可以使用certain priority启动。选择一个低值,如Background或ContextIdle,你永远不会重载GUI 然后确保定时器不会咬得太多而不能咀嚼。一次只能有一个(或几个)项目。调整此部分,以便GUI尽可能多地处理,但不能再处理。运行时调整是免费的,因为你被绑定到调度程序。
并且(仅在需要时)您可以使用Queue1 = new BlockingCollection<MyItemType>(MaxItems)
,以便此队列不会溢出。