yes there’s absolutely no need for UI to be multi-threaded. You can do stuff in the background but IMO multi-threaded UI is completely useless.
You have an event loop where you poll for input => propagate changes => commit changes => rerender UI. Normally you
might have poll => propagate => rerender, but when you delay the changes you can represent everything in a shared reference, and when commit them you have a single source which takes the 1 mutable reference Rust allows.
UIs can spawn jobs in the background, but that's an explicit thing programmer has to do, and evidently they forget all the time. It took Apple over a decade to mostly fix "beachballing" problems plaguing Finder.
Another problem that may be Cocoa-specific is that it can hook UI-changing observers to objects, and then these objects become unsafe to use in multi-threaded programs (including those background jobs you should be using!)
Yes, but the 'background threads' are usually not working on the UI.
So it's not rocket science to just coordinate access to the tree.
It'd be nice to have an architectural way of doing that, but frankly, just living with the idiom ("Don't Do This") works well, and some frameworks put in runtime checks, i.e. QT will crash I think in some cases if you try to mess with the tree on the wrong thread.
Not really UI, but wasn’t one recentish game really performant due to it using Vulkan, but in a multi-threaded way? Not sure whether it would benefit traditional UIs though.
Intensive graphics rendering is something which does deserve the GPU and multiple cores. But most "UI" as we see it shouldn't be that intensive. UI drawing is usually on the GPU but stuff like handling inputs, updating the UI tree, should be fast enough on one thread.
You have an event loop where you poll for input => propagate changes => commit changes => rerender UI. Normally you might have poll => propagate => rerender, but when you delay the changes you can represent everything in a shared reference, and when commit them you have a single source which takes the 1 mutable reference Rust allows.