Hacker Timesnew | past | comments | ask | show | jobs | submitlogin

It isn’t that it’s invisible. It’s just that you didn’t get it until now.

I am not saying that to belittle the author. This is more an observation of how programming seems to have gone from understanding both yourself and what you are doing to shopping bits and pieces and then gluing them together.



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.


How 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.


> 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.


Async 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.


Sure, 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).


It 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.


Ah! 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).


For 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....). 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.


Except, 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.


Go 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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: