Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with unresponsive UI in high-volume model update scenarios

We're using Qt 4.8.2, and we have a model/view design (subclassed QAbstractItemModel and QTreeview, specifically). The model/treeview follows the typical philosophy where the view drives the model - we don't populate the model until the user expands the corresponding treeview nodes.

Once a node has been expanded & data is visible, it is subject to display updates that occur in worker (non-UI) threads. Right now, when a worker thread produces a change that may affect the treeview, it emits a "change" signal, which maps to a slot in our model.

The problem is that these change signals can be emitted with great frequency (say, 1500 events over a second), sometimes, but they may apply to what the treeview currently displays (and can therefore be ignored). When this happens, the UI thread becomes unresponsive as (I presume) the signals all queue up and the UI thread has to deal with them before it can resume responding to user interaction.

The time it takes to respond to a change signal is very small, but it appears that the UI thread only "eats" the signals after a small delay - presumably to avoid excessive updating resulting in screen flicker or other annoyances.

The result is that the UI remains frozen for 5 or 6 seconds, with very low CPU activity during this time (presumably because the signals are coming in fast enough the handler is still waiting for break in the action); once all the signals are queued up, the thread finally consumes the work in the queue and resolves it in a few milliseconds.

I have several thoughts on this:

  1. Is there some setting such that I can increase the aggressiveness by which the UI thread handles incoming signals?

  2. Is it feasible at all to manage the updates of the model in a separate thread? My instinct is to say no - it would seem the Qt machinery is too dependent on exclusive ownership of the model, and putting the appropriate lock protection around its access would be complicated and violate the whole point of the slot/signal paradigm.

  3. I can think up more complex schemes to deal with this signals in a secondary thread; for example, the UI could maintain a separate multithread-visible (non-model) data structure that could be queried to determine whether a change signal needed to be sent. Similarly, I could maintain a separate queue that the worker threads use, where I could batch up change events into a single signal (which I could deliver no more than twice a second, for example). But these methods strike me as a bit byzantine for a problem that I assume must not be totally uncommon in the domain of Qt UI programming.

like image 462
Steve Broberg Avatar asked Oct 21 '22 11:10

Steve Broberg


1 Answers

We had a similar application with large updates to underlying data. The question comes down to:
1500 updates per second will result in how many changes in the GUI?
If the answer is there will be less than 6 changes, then the model should only emit 6 data changes per second. If this is the case, when underlying data changed, check if this change will change the GUI or not, only emit data changed signal from model when necessary.
If the answer is there will be more than 6 gui changes per second, the answer we have is no human being can see more then 3 changes per second. The underlying data change should not update GUI at all. Use a 250 milli second timer, in the timer event, check the cells needs to be updated, and update them.

like image 66
m. c. Avatar answered Oct 23 '22 11:10

m. c.