Hacker News new | ask | show | jobs
by jayd16 2220 days ago
Sometimes you want to block the main thread, or at least finish what you were doing. With async/await and cooperative concurrency you can be explicit about what will run on a thread. You retain control of the thread until you yield or await. You can ask tasks to complete on other threads or post back to the main thread. You have a lot of control. Its easy to write code without locks that runs concurrently on the main thread but is still able to build a UI in a threaded way.

I don't really know how go UI frameworks work. How do you have multiple, preemptively scheduled goroutines on the UI thread but without critical sections? You have to use channels and message passing back to a main thread manager to handle this, yes?

I think Java's Loom would have the same issue but again, I don't really know. Perhaps worrying about a UI thread is 'fighting the last war' and we should work on new UI paradigms in these new language features.

2 comments

I'm working on a UI app in Go, yes I think you'd use channels and message passing but it doesn't look all that bad in practice.

First you'd probably call runtime.LockOSThread() to tie a goroutine to an OS thread if the native API you're coding against needs that (like Cocoa, OpenGL, etc).

To perform work on the main thread using closures is probably the most convenient way. So you just have a RunOnMainThread(func(){...}) that puts the closure on a channel to run on the main thread (or uses some similar feature from the underlying native framework).

It's not terribly inconvenient - it's similar to the old Cocoa / UIKit performSelectorOnMainThread: method except that you have closures to make things simpler.

There's probably a little syntactic overhead compared to if you had several async/await functions running concurrently on the main thread. But on the other hand it's probably a bit easier to reason about, since the flow of execution on the main thread is very straightforward (if you have multiple async/await functions running at the same time on the main thread, it seems like every time they await a result they'd have to worry about other code being run on the main thread, and make sure they release any locks, etc).

You can spawn a goroutine that immediately waits on a channel, so that it will not actually do anything until you want it to. This seems at least as expressive as a single-threaded switch() primitive. I think it can also express the threaded async pattern you want, but I'm not sure.
Are there any popular, idiomatic Go UI frameworks I could explore?
You can try your luck with https://github.com/avelino/awesome-go#gui

I explored the landscape earlier this year when I was building a GUI version of a CLI tool written in Go. I was throughly disappointed by all the “native Go” and non-webview options — narrow selection of widgets with basic functionality missing, UIs ranging from lack of polish to horrendous looking (that makes Java GUIs look like godsend), lots of bugs, etc. I ended up using the Qt binding which, despite its own share of problems, at least worked fairly reliably and didn’t constantly get in my way in every way imaginable: https://github.com/therecipe/qt