Saying the average joe doesn't care to understand what his/her Lang is doing under the hood which will doom them to repeat complexity that many here will respond with "duh" is not justification that a Lang is better - because it supports that behavior "better".
I don't know erlang that well but I'll be damned if I don't spend the time to find out how to properly do M:N with efficient tail recursion.
If one doesn't care for efficiency at all then who cares about benchmarks?
In my comment I purposely mentioned erlang because to implement algorithmic efficiency you must have domain expertise.
"I don't know erlang that well but I'll be damned if I don't spend the time to find out how to properly do M:N with efficient tail recursion."
Tail recursion is an efficiency, doing it right in erlang requires domain expertise.
Building new features and adding value is business. Someone with domain knowledge in any of the langs will be able to implement those business values in the best possible way.
If your business is built with shitty coders doing shitty things you will eventually find yourself in hot shit. Even if it takes 5 years. What comes around goes around.
I would take the domain knowledge developer over any monkey anytime. That's your 10x developer. That's who built all that awesome open source stuff you use all day. Not the business feature value guy.
He builds businesses that fail 99% of the time. That other guy building that obscure Lang which turns out useful for that niche topic (I.e concurrency) lives on even in concept to build or inspire other langs/ers.
You see, that domain expert knows to pick the right algorithm for the right job.
He knows the right Lang for the right job.
Even if that job is only business value.
Long live domain knowledge experts and those who wish to attain it.
also go is not better than all of these languages. what we learned here, is actually that go is easier since you only have one common way to do this task. go has goroutines, but go doesn't have runnables, futures, actors, completionstages, executioncontexts. GO has GOMAXPROCS and not dispatchers, thread pools, etc..
Also the JVM eve Java only code would actually beat golang in many ways, but thats nothing you should be scared of. Golang is 1 1/2 year old, the JVM lives like 20+ years and they spent numerous times about the GC implementations (they could be even changed so that you could use a better GC for conurrency or for parallelism or for synchronous execution). Go is good for the task it is created. Other languages maybe tend to be more general so that you could do many things and due to their years of knowledge they are actually more optimized than go could be / they could be more optimized than go could be.
Some of us (most of us, I would contend) who have been successfully programming highly concurrent software without them for 20+ years are totally OK with that.
I work on parallel software every day and I would not be OK with having threads and channels as my only tools. I would agree that they're usually the best thing to reach for initially, but it's essential to be able to have low-level control over the scheduling if you want to get good parallel performance out of the hardware. I have workloads that today result in 3x speedups on 4 cores but would become slower than the sequential algorithm on 1 core if I were to rip out the highly-tuned parallel scheduler and replace it with threads and channels.
To be fair, though, I'm working on CPU-bound software and if my workload were I/O bound I'd likely have a different outlook on this.
Java's GC is generational, allowing bump allocation in the nursery. That is a huge advantage.
In the HotSpot VM, you can tune the GC to get any type of max garbage collection pause you want (-XX:MaxGCPauseMillis). This is basic functionality that any concurrent garbage collector supports. The downside, of course, is that pauses will happen more frequently, reducing throughput. That is why just saying "it's under 10 ms, so it's really fast" is very misleading: when your GC is interruptible, you can of course get any max pause time you want. But the GC may not be able to keep up with your allocation rate, and it may start being invoked too often. That's why you need to not just look at latency, but throughput--something that sound bites won't capture.
Pause time is only one metric that's relevant when looking at GC, another very important one is throughput.
In fact you can get very low (10-50 msec) pause times with the latest JVMs even with very large heaps, you can just request it at the command line, but you'll pay for it with slower execution. There is always a tradeoff. Go doesn't have anything fundamentally new in this field.
There is a report here on an adapted HotSpot (not integrated into the mainline JVM though) that gives <10msec pause times at the 99th percentile and an 8 gigabyte heap:
http://welf.se/files/OL15.pdf
But you pay for it with a 15% CPU overhead.Go's GC seems to actually do a full concurrent mark/sweep of the entire heap every single time. That suggests to me that throughput could be rather poor.
But the lowered throughput has to be present as you are scanning the heap and you have enabled the write barrier to make the concurrent scanning work its invariants. In fact, the newest versions will make aggresively allocating goroutines run slower by using some of their timeslot when they request data do run the mark phase.
Not to mention that you lose bump allocation in the nursery. Nongenerational GC is a lose-lose all around.
See the -XX:MaxGCPauseMillis=NNN argument, you might be able to set it to 10ms on highly performant hardware.
Summing a bunch of numbers is a silly task anyways
How a language handles misses/blocking/threading is more important than what it can do in a perfect cpu only world.