In many applications the 'UI thread' is special and framework UI updates must be dispatched from this thread.
However, in order to avoid locking the UI slow tasks are executed in background threads and the results propagated back to the UI thread to be displayed.
Different frameworks solve this in slightly different ways; for example:
In WPF the
Application.Current.Dispatcher
can be used to spawn a task that runs in the UI thread.On android, you can use
runOnUiThread
to push an action onto the event queue for the UI thread.In QT you bind an event handler using their signal/slot system to receive notifications from the background thread and update using the UI thread event handlers.
In iOS you use something like
dispatch_async(dispatch_get_main_queue()...
to trigger a task on the UI event queue.
All slightly different, but in general the pattern is clear: the background thread creates a Task
which it then schedules to be executed on some TaskQueue
which the UI thread periodically services in a synchronous manner.
However, I'm not convinced this is actually best practice.
Certainly for few, large background tasks it is reasonable.
...but when you have a large fan-out into sub-threads, and a one-to-one delegation of task-complete -> UI task, this simply smashes the UI with lots of small update tasks, defeating the purpose of moving work into backgrounds threads in the first place.
It seems much more beneficial to have an application level aggregation layer that combines and filters UI updates and only feeds the necessary ones through to the actual UI thread; in many ways this is effectively what the 'Virtual DOM' in react does (but without threads).
So, there's the use case.
Here's the question:
- What's an effective pattern to write such a thread aggregation layer?
(...and notice that because this is a data-only operation, there is no requirement that this layer is served by a single thread like the UI thread event loop; it may in fact be optimal to service in-coming updates via a thread pool)
...but when you have a large fan-out into sub-threads, and a one-to-one delegation of task-complete -> UI task, this simply smashes the UI with lots of small update tasks, defeating the purpose of moving work into backgrounds threads in the first place.
The purpose of these mechanisms is to make the UI more responsive by preventing blocking operations that will freeze user input, thus allowing the user to interact freely with the UI. Small updates don't generally have any impact on this freedom, unless you have an enormous amount of them.