Your statement holds only if GOMAXPROCS is 1, which granted used to be the default, but was always able to be increased, and the default now is the number of cores on the machine.
So, things changed since that time. OK, nice to see Go evolves. Interesting, how many code in production got broken during upgrade to Go 1.5 due to this backwards-incompatible change. Overall situation seemed totally reasonable to me at that time: Go is a language for average programmer, so it should prefer safely over runtime performance; and coding cowboys who are comfortable with mutexes, interlocked instructions, memory barrier instructions, and lock-free data structures will use C/C++ anyway.
numCPU := runtime.NumCPU()
ret := runtime.GOMAXPROCS(numCPU)
From 1.5 the process the default value of MAXPROCS is total CPUs on the machine.
So its not 'reduced parallelism compared to C/C++' rather the concurrency infrastructure (channels etc) makes it transparent to the programmer. I don't have to worry about creating a threadpool myself like C/C++ and Java. So overall there is a net gain, in my understanding. Am I wrong any where in this?
Unless the qualifier is "popularized among Ruby and Python people," and, well, sure, but the number of Prometheuses to bring fire to those folks is large and ever growing.
I have simply never seen another language that makes it as easy as Go does to reason about parallelism/concurrency (maybe Erlang).
The select pattern maps directly to any number of interupt style programming abstractions that are available in every language I've programmed in the last 15 years.
Quite simply I find the go concurrency story primitive to the point of painful. I'd love to figure out why my opinion on that is so far outside the common refrain
Having Java's concurrent stuff is nice, don't get me wrong, but I can understand it not being the biggest priority in the world to go rebuild that later. As I've mentioned elsewhere in this thread, there are much bigger beefs.
You are implicitly casting as something to be praised one of the greater missteps of Go.
You could perhaps compare it to Python, where async functionality has a solid and well established userland implementation in Twisted, but where asyncio still made a big splash around the community. Language constructs matter.
"Misstep" was the kindest phrasing I had for the kind of trainwreckish design decisions and institutional reification of developer mediocrity that get you to what you're defending.
Your chosen tools have contempt for you, and it mystifies me as to why you would defend them for their failures.
Go's channels are effectively a locking message queue (Java's had one of these since at least Java 5) plus a (usually global) thread pool. Not too long ago I implemented the moral equivalent in C++11, using only the standard library and in a unit-testable format, in forty-eight lines. Selecting across them is nice syntactic sugar, but is likewise able to be mimicked in plenty of other languages. Or, alternatively, I can use way more pleasant abstractions like Akka or Celluloid in not-Go languages (sending up Erlang when Akka provides a very similar experience in Scala or Kotlin--even Java, if you're using Java 8--is...curious).
I guess you can make an argument for TOOWTDI, but I don't find that to be persuasive when the OW in question is middling.