11 comments

[ 2.8 ms ] story [ 36.2 ms ] thread
Very neat!

> Go calls its threads goroutines as a pun on coroutines, to indicate that they're lighter than real operating-system threads.

A pun? Maybe. But the point of calling them go-routines instead of co-routines is that they _are not coroutines_.

There isn't a requirement of cooperation on the programmer's part as there usually is with coroutines (at least as I experienced them in Python, having to place Yield() calls to let other coroutines run).

With goroutines the cooperation is handled by the implementation/compiler -- i.e. Yield() calls are automatically inserted by the compiler -- rather than by the programmer manually by hand.

> With goroutines the cooperation is handled by the implementation/compiler -- i.e. Yield() calls are automatically inserted by the compiler -- rather than by the programmer manually by hand.

The compiler only inserts yeilds at some call sites. It's not a total solution like real preemptive scheduling, so you still need to be careful.

Newer Go versions (1.2 I think?) use preemptive scheduling so you don't have to do anything special: that's my point entirely.

Goroutines by specification have the potential to run all at the same time, in the exact way that OS-level threads do.

In older _implementatoins_ of Go, goroutines were not preemptively scheduled, and exactly as you say you had to be careful.

>A pun? Maybe. But the point of calling them go-routines instead of co-routines is that they _are not coroutines_.

Well, the pun explanation makes more sense.

Because the mere fact that "they are not coroutines" doesn't explain their similar-to-coroutines name.

Or rather, it does explain why they are not called "coroutines" but does explain why they were named to sound like coroutines at all.

Would be nice to mention it's from 2011 in the title.
Pretty good article, but a few things stood out to me as questionable:

> In the CSP model, message delivery is instantaneous and synchronous. The Go implementation is slightly different: Messages are buffered in channels in much the same way that Erlang buffers messages for delivery to processes. [...] Go unfortunately misses out on one of the things that makes CSP easy to reason about. The synchronous nature of CSP message-passing [...].

Go has both buffered and unbuffered channels; unbuffered channels are the default. Most code uses unbuffered channels, because, as the author correctly points out, unbuffered channels are much easier to reason about.

Sometimes you do want buffered channels though, although you quite often want a buffer size of only one or two.

Buffered channels are the reason why goroutines are not coroutines in the traditional sense (there was a sibling question asking about that). Unbuffered channels and GOMAXPROCS=1 (the default) give you coroutines. Go gives you more if you need it.

We are using Erlang and trying out Elixir on one of our projects, and so far it is working out very well - a big chunk of that comes down to the way concurrency is handled especially in the context of letting things fail, accepting they will fail, and designing with that in mind. A similar attempt with Go was perhaps not so successful with the need to bear in mind how Go models errors and failure within code, which ended up cluttering up the code quite considerably.
This is probably the most lucid and approachable discourse I've read on the topic. Thanks a lot for sharing this!