如何在高容量模型更新方案中处理无响应的UI

时间:2014-03-26 17:13:29

标签: c++ qt model-view-controller

我们正在使用Qt 4.8.2,我们有一个模型/视图设计(具体是QAbstractItemModel和QTreeview的子类)。模型/树视图遵循视图驱动模型的典型原则 - 我们不会填充模型,直到用户扩展相应的树视图节点。

节点扩展后数据是可见的,它受制于工作(非UI)线程中发生的显示更新。现在,当工作线程产生可能影响树视图的更改时,它会发出一个"更改"信号,映射到我们模型中的一个插槽。

问题是这些变化信号可以以很高的频率发出(例如,一秒钟内发生1500次事件),但有时它们可​​能适用于树视图当前显示的内容(因此可以忽略)。当发生这种情况时,UI线程变得没有响应,因为(我推测)所有队列的信号都会排队,并且UI线程必须先处理它们才能恢复用户交互。

响应变化信号所需的时间非常短,但似乎只有UI线程“吃掉”#34;一小段延迟后的信号 - 大概是为了避免过度更新导致屏幕闪烁或其他烦恼。

结果是UI保持冻结5或6秒,在此期间CPU活动非常低(可能是因为信号进入速度足够快,处理程序仍在等待操作中断);一旦所有信号排队,线程最终会消耗队列中的工作并在几毫秒内解决它。

我对此有几点想法:

  1. 是否有一些设置可以增加UI线程处理传入信号的攻击性?

  2. 在单独的线程中管理模型的更新是否可行?我的直觉是拒绝 - 看起来Qt机器太依赖于模型的独占所有权,并且在其访问周围放置适当的锁保护将是复杂的并且违反了插槽/信号范例的整个点。

  3. 我可以想出更复杂的方案来处理辅助线程中的这些信号;例如,UI可以维护单独的多线程可见(非模型)数据结构,可以查询该数据结构以确定是否需要发送变化信号。类似地,我可以维护一个工作线程使用的单独队列,在那里我可以将事件批量更改为单个信号(例如,我可以提供不超过两次的信号)。但是这些方法让我觉得有点像拜占庭式的问题,我认为这个问题在Qt UI编程领域并不是完全不常见。

1 个答案:

答案 0 :(得分:3)

我们有一个类似的应用程序,对底层数据进行了大量更新。问题归结为:
每秒1500次更新将导致GUI中有多少更改?
如果答案是少于6次更改,那么模型应该每秒仅发出6次数据更改。如果是这种情况,当基础数据发生变化时,检查此更改是否会更改GUI,只在必要时从模型中发出数据更改信号。
如果答案是每秒将有超过6次gui更改,我们得到的答案是没有人能够看到每秒超过3次更改。基础数据更改根本不应更新GUI。使用250毫秒计时器,在计时器事件中,检查需要更新的单元格,并更新它们。