The example under "Communicating by sharing memory" isn't correct, despite the author claiming that "it works". It's a very common example in concurrency 101 (updating a value). The fact that the author claims that it's correct is pretty concerning to me.<p>Adding a print(len(ints)) at the bottom of the function:<p><pre><code> $ go run test.go
5
$ go run test.go
8
</code></pre>
More on-topic, channels have their own tradeoffs. I often reach for WaitGroups and mutexes instead of channels, because things can get complicated fast when you're routing data around with channels...more complicated than sharing memory. I don't think it's good advice to broadly recommend one over the other--understand their tradeoffs and use the right tool for the job at hand.
I guess I wish this was a bit more in-depth as to what "go" can do with channels or goroutines, but maybe I've just been using languages where all this is already possible. The article is a nice cursory glance, I just want to learn more :)<p>I mean the first example it looks like is using a Mutex, and then (b)locking on it, and the second just looks like having a queue of messages (mailbox) that it rips through (like the actor pattern).<p>Some questions I've got after reading this...<p>How does the go-runtime (?) schedule these calls? Does it manage an internal thread pool? Is the scheduler asynchronous, parallel, or both? How do you manage contention or back pressure if I begin to flood messages to to one channel (or many)? How many channels can I have open and what are the limits? Can I still lock the system stupidly using channels, if so, how (or how not)?<p>Edit: Truly, I'm curious because as I researched asynchronous programming and efforts to better future proof my career (years ago) as we began really increasing core counts-- Go never stood out. It's a fairly practical language, yes, but if I want a better paradigm for asynchronous programming the future it really isn't there (IMHO). BEAM stood out as something unique, the JVM stood out as something even more practical, and Rust stood out as something performant (with the serious caveat of not being C or C++), while Go has always seemed like an odd one to me... People talk about channels and goroutines like their special but they seem pretty damn run of the mill to me... WAT AM I MISSING?
I do like that select statement which hits the first case that has its channel ready with a message. That's very nice. And having channels in your standard library is brilliant and everyone should do it.<p>A shame about the shared memory thing though. I firmly believe that designing a language where memory is shared by default is a Bad Idea. You should probably provide a way to allow it when you really need it (for performance, usually, in very very very carefully-designed code), but having memory sharing by default is a source of soooooo many bugs.<p>I know, because I've caused most of them.
I've found channels create more complexity than their usually worth and it's often simpler, more readable, and more maintainable to just use a sync.Mutex or sync.RWMutex.
Channels are really nice; I love writing "workers" with them and sending errors and "status messages" with a simple `status <- "starting supernode"`/`errors <- err`; doing this with i.e. Node's async/await is just so much more complex.
For anyone interested in using channels and coroutines in PHP, swoole (<a href="https://github.com/swoole/swoole-src" rel="nofollow">https://github.com/swoole/swoole-src</a>) provides a reasonable implementation!
off tangent, but I really like that syntax of defining types especially for channels:<p><pre><code> type Foo(chan<- int)
</code></pre>
instead of what I usually see<p><pre><code> type Foo chan<- int
</code></pre>
unfortunately it doesn't appear compatible with gofmt (entirely), which changes it to:<p><pre><code> type Foo (chan<- int)
</code></pre>
I still think it's a good pattern for channels though. It makes it a lot clearer what the type is especially if you have a slice of channels:<p><pre><code> type Foo []chan<- int
</code></pre>
vs<p><pre><code> type Foo [](chan<- int)</code></pre>
The only thing golang has going for it is "goroutines". Now that all other popular languages are getting some variant of async (e.g. C#) or green thread implementations (e.g. Java), it will be tough to advocate for golang for new projects given its severe shortcomings.