Saying that Go "adds even more complexity to concurrency" doesn't scan. It lets you write code using whichever model you prefer--CSP or mutexes.
It is definitely true that CSP is hard for many problems... but locks and shared memory is also hard for many problems. There is no silver bullet, so you need both.
Of course you can do whatever you want, but Go is a very opinionated language and there's an opinionated community behind it. Which it's fine. But then when you ask "how to do X using locks," the only thing people respond is the mantra of "don't communicate by sharing, share by communicating". Which doesn't help in any way. Then people ask complex questions about using channels and others say "why don't you just use locks?" That's why I think Go adds more instead of alleviating the complexity of writing concurrent programs.
I didn't quote that part because it's the most nonsensical part of the comment.
You've apparently been frustrated by your interactions with the members of the community and that's a fair complaint, but you haven't translated that complaint into a criticism of the Go language itself.
My experience is--CSP is a reasonable default, and "select" is a really nice language feature to have around, and mutexes / condition variables are still available when you need them. Mutexes aren't a good substitute for CSP and CSP isn't a good substitute for mutexes. You should have both available.
> CSP is hard for many problems where classic shared-memory using locks and atomics are well defined (think of classic concurrency programming textbooks).
This isn't a problem with Go's particular flavor of CSP, this is just a fact--it can be hard to translate simple modules that use locks into modules that use a CSP paradigm.
> Now with Go, you have this extra problem of "should I be using channels or locks?"
I think you're arguing against yourself here... if it's important to answer the question "should I be using channels or locks?" correctly, then wouldn't you be in a bad situation if the language only provided channels or only provided locks?
This is no different from the problem of "should I use recursion or iteration?" or "should I use a tree or a hash table?" Some times, either option is workable, but at other times, one of the options is better than the other. CSP versus locks is the same thing, it's just another decision you have to make when programming.
I typically use shared memory by default (mostly mutexes and waitgroups), and generally only use channels when I'm working with task queues, which is where they really shine.
No races aren't an inherent part of concurrent programming - you can make it safe.
> If it has to happen in a particular order, you can't do it concurrently.
I didn't say things had to happen in a particular order, just that their results are merged in a well-defined order. Otherwise you could test against one particular ordering that happens by chance, and then in production you get another order by chance that you didn't test against and it doesn't work! That's what you get with Go.
Messages coming out of order are a cause of race conditions.
> You just want to structure your messages in a way that the order doesn't matter
Right... just program without bugs and you won't have any bugs! The problem is people forget to do this, or think they're doing it when they aren't, and they get a failure one in a million. I've done it myself! Why not use a system where it's impossible to depend on message order in the first place?
Are you suggesting that one should strive to solve concurrency problems with parallel computing approaches?