基本问题
您看到繁忙指标停止的原因是因为您SomeMethodWhichDoesWork
花费的时间太长。在它运行时,它会阻止 Dispatcher 上发生任何其他工作。
为处理动画而生成的 Input 和 Render 操作的优先级低于 Normal,但优先级高于 Background 操作。但是,Dispatcher 上的操作不会被更高优先级操作的入队中断。因此,即使是后台操作,渲染操作也必须等待正在运行的操作。
关于观察 DispatcherScheduler 的警告
ObserveOn(DispatcherScheduler)
默认情况下,将以 Normal 优先级推送所有内容。较新版本的 Rx 具有允许您指定优先级的过载。
需要强调的一点是经常被忽略的一点是,一旦项目到达,DispatcherScheduler 就会将它们排队到 Dispatcher 上,而不是一个接一个地到达。
因此,如果您的 3000 个项目都非常接近,您将在 Dispatcher 上备份 3000 个正常优先级的操作,阻塞所有相同或更低优先级的操作,直到它们完成 - 包括渲染操作。这几乎可以肯定是您所看到的 - 这意味着即使您在后台线程上完成了 UI 更新之外的所有工作,您可能仍然会看到问题,具体取决于您的 UI 更新的繁重程度。
除此之外,您应该检查您没有在 UI 线程上运行整个订阅 - 正如 Lee 所说。我通常编写我的代码,以便我Subscribe
在后台线程上而不是使用 SubscribeOn,尽管这也很好。
建议
无论你做什么,都尽可能多地在后台线程上工作。这一点在 StackOverflow 和其他地方已经被彻底完成了。以下是一些很好的资源:
如果您想在面对大量小更新时保持 UI 响应,您可以:
- 以较低的优先级安排项目,这很好也很容易 - 但如果您需要某个优先级,那就不太好
- 将更新存储在您自己的队列中并将它们排入队列并让您运行的每个操作在最后一步调用队列中的下一个项目。
更大的图景
值得退后一步,看看更大的图景。
如果你分别将 3000 个项目连续转储到 UI 中,这对用户有什么影响?充其量他们将运行刷新率为 100Hz 的显示器,可能更低。我发现每秒 10 的帧速率对于大多数用途来说已经足够了。
不仅如此,据说人类一次不能处理超过 5 到 9 位的信息——所以你可能会找到比一次更新这么多东西更好的方法来聚合和显示信息。例如,利用主/详细视图而不是一次在屏幕上显示所有内容等。
另一种选择是查看您的 UI 更新造成的工作量。一些控件(我在看你 XamDataGrid)可能有非常冗长的测量/排列布局操作。你能简化你的动画吗?使用更简单的可视化树?想想看起来像圆点的流行忙碌的微调器 - 但实际上它只是在改变它们的颜色。一个很好的效果,实现起来相当便宜。值得对您的应用程序进行概要分析,以了解时间的去向。
我也会考虑从前到后的整体方法。如果您有理由确定要一次更新这么多项目,为什么不缓冲它们并分块管理它们呢?这可能会一直追溯到源头——这可能在某处的服务器上?在任何情况下,Rx 都有一些不错的操作符,比如Buffer
可以将单个项目的流转换为更大的列表 - 它具有可以按时间和大小一起缓冲的重载。