5 ms·
Not really, "invisible" is a fair way to describe complexity that developers never interact with. Especially when most other popular languages forces developers
by ferdowsi 5y ago
Not really, "invisible" is a fair way to describe complexity that developers never interact with. Especially when most other popular languages forces developers to deal with irritating async/await bookkeeping when it comes comes to concurrency.
- zozbot234 5y agoHow so? The point of async/await is to reduce bookkeeping. The Go model is at its core an implementation of M:N user threads, and it creates plenty of complexity wrt. e.g. interfacing with other languages. Which is why M:N threading was mostly abandoned elsewhere.
- klabb3 5y ago> it creates plenty of complexity wrt. e.g. interfacing with other languages Hmm I'm not sure I get this point. Do you mean in comparison with async? Async cross language interfaces should need the same type of continuation mechanisms (eg poll or completion based interop with an event loop) as green threads, no? I think of async as a primarily syntactically explicit construction, while both look similar in ABI, with a virtual stack. If not, I'd love to know why.
- int_19h 5y agoAsync with explicit await is basically just syntactic sugar for continuation callbacks. The "virtual stack" that results can thus be expressed entirely in terms that the C ABI understands: a callback is just a C function pointer + pointer to the struct representing the virtual stack frame.
- klabb3 5y agoSure, but then the callee is responsible for any async io anyways - meaning it needs to either run its own event loop or use a thread pool if it wants to do IO, right? What I mean is that without a protocol/ABI to access the caller's runtime, you'd have to use your own. For instance, Rust has explicit async/await but the poll method has a pointer to a waker, and a non-standard global/thread local variable is used to communicate with the runtime. Specifically it needs to access the reactor (in Rust lingo).
- int_19h 5y agoIt depends. You can treat it as implementation detail, with multiple loops if needed. Or you can use a shared event loop propagated over the same C ABI. Either way, this all maps nicely to C FFI. But true green threads don't - since every frame is interruptible by default, all languages involved must use the async stack for all functions, in a way that's compatible with them all. Like tail calls, this is an ABI-level thing that you can't slap on top of the existing C ABI.
- klabb3 5y agoAh! Finally I think I'm getting the distinction, thanks for being patient. I also agree about the ABI issue - explicit callbacks is much simpler. It appears as Go doesn't expose green threads as per your definition for it's FFI though, but rather an even simpler synchronous interface in both directions. This makes it impossible to interface with the event loop, and one must use threads. For Go->C, at least, this should not block the runtime since the Go runtime spins up more threads in case of long running synchronous calls (their version of pre-emption).
- int_19h 5y agoFor an opposite example, consider async/await in C# - you're not restricted to .NET when using it; it also supports e.g. the native async OS APIs in WinRT (which are callback-based on ABI level: https://docs.microsoft.com/en-us/uwp/api/windows.foundation.iasyncinfo https://docs.microsoft.com/en-us/uwp/api/windows.foundation....). Ditto for co_await in C++20. Go's approach leads to an insular ecosystem that tends to reimplement everything, because that's the only way to get this transparent async throughout.
- bborud 5y agoExcept, you never interact with the (os) threads. So it isn't complexity that the programmer deals with. Async/await also doesn't address data sharing, so we're not even talking about the same thing. You can implement async/await-like code that emulates other languages in Go, but it would be a somewhat pointless exercise since you have channels, which offer a much safer and better mechanism for communicating state.
- bborud 5y agoGo is marketed as having a programming model that is heavily influenced by CSP. This is one of the big selling points for Go and it is at the core of how it offers concurrency. It is hardly some footnote that is hidden away. It is pretty much in your face.