Moreover, the core assumption that native == faster is not true. One advantage of the jvm is that as a program runs, the runtime can internally profile and adjust the byte code on the fly in order to increase performance.
Please note that Windows and OS X is benchmarked on different CPUs!
You're welcome to re-test at dual-boot MacBook together so we can meaningfully compare OS X/Windows
Testing with allocation in all languages will give a better idea of performance (and I won't be surprised if .Net core fares very well).
I think there are by far too many knobs to turn to make this comparison meaningful.
Of course the results are more or less expected. JVM is by far the worst, because it uses OS-level threads, while Go and Erlang use userland threads, which are way cheaper to spawn and manage.
[edit] According to some other comment around here, Scala is supposed to use userland threads as well.
Yup.
However, Actors are not threads, so in a way it's like user threads. One million actors will be scheduled to run on a pool of OS threads.
1. That the time (including start-up time) for something on the JVM would be longer because the JVM needs to start up.
2. That Go producing a native binary is automatically faster at things.
In reference to the first, the benchmark timings are started when the software actually starts running.
In terms of the second, being a native binary doesn't mean faster. Go still has a runtime. It's just included in the binary.
Go's performance advantage is probably a few things. Go was made to spawn millions of goroutines and Go uses primitive types. I don't know all that much about Scala, but I believe it doesn't do primitive types which means that every one of those Int objects requires following a pointer to get to the value. That's overhead. EDIT: this looks like it's wrong as Scala has a bunch of pre-defined classes that extend AnyVal and correspond to primitive types in Java.
It also looks like the Scala code is passing back a Long even when the value is still small enough to fit in an Int. That's doubling the amount of memory when that memory only needs 64-bits near the end stages. By contrast, the Go code does `sum := 0` which I'm not actually sure how that's working. If I initialize a 32 bit int without specifying it, I see that I wrap around (http://play.golang.org/p/PiiMZmEzKp). So, I'm not sure how initialising it to 0 and then adding to something over an int32 works. Maybe Go uses a different default int depending on platform?
Go's implementation is also simpler. In the Scala version, there's a receive method and the sub-actors just pass back when they're done potentially causing a bunch of switching. Go, on the other hand, creates all the goroutines and only when that's done starts receiving from them. In the Scala version, the program might think that there's value in switching from creating the sub-actors to receiving from them - and they should pass back very quickly. The implementation here in Go doesn't allow for that switching.
When dealing with something as synthetic as this, all of these little things matter.
No? Erlang and Scala both have JITs. The JVM does quite a bit more optimization than Go's compilers do.