
Comparing clojure and node.js for speed - Swizec
http://swizec.com/blog/comparing-clojure-and-node-js-for-speed/swizec/1593
======
theturtle32
This is totally not the right benchmark for comparison. Node's JS execution is
single threaded, and it's well known that it's not the appropriate choice of
platform for CPU-bound workloads. Its main selling points are high concurrency
in terms of number of network connections, event based design, and JavaScript
as a programming environment. While it may be fairly good at doing computation
because of V8's strong optimizations (it compiles JS functions to x86 assembly
- JVM does similar things) it is not good at also sustaining high concurrency
in the process. Those CPU bound operations will block everything else until
they're done unless you code your functions to yield and cooperatively
multitask.

------
jshen
This is a poorly implemented benchmark. He's including the startup time of the
jvm, he's not warming up the jvm, and he's not type hinting the clojure code.

I don't know node, so I don't know if he's making similar mistakes on that
side.

~~~
Swizec
I tried with type hinting the clojure code, it was slower.

Startup time for the jvm seemed fair, because node has to start up as well.
This should count into the overall time imho.

~~~
jshen
you should calculate the time within clojure and node and output it. This will
take away the startup time. You should also warm up the jvm.

I may play with the type hints tonight if I get time. It shouldn't make it
slower.

------
UncleOxidant
As soon as he said: "The comparison I chose to go for is hard computation" I
knew that node would be shown to be the loser. node isn't going to be great
for lots of long computations - even node fans will tell you that.

We are finding node to be quite nice, though, for our real-time web app (which
includes chat communication, and game like features). But we don't have any
long-running calculations to do. I suspect that if we did we'd have them run
in a separate server process... maybe even writing the compute intensive code
in C++.

tl;dr: the type of benchmark chosen is stacked against node.

------
tomazmuraus
Nothing new here.

Node wasn't ever really meant to be used for CPU intensive tasks - especially
the ones like this which you can fairly easy parallelize.

~~~
UncleOxidant
Exactly, If I were using node and needed to calculate primes I'd probably
write some C++ code to handle that part and run it as a server in a separate
process that can be called asynchronously from node.

~~~
calpaterson
Hopefully you'd try another algorithm before you did that ;). Primality tests
are one of the most highly understood and well documented areas of CS - trial
division has been obsolete since, what, 1640?

~~~
btilly
_... trial division has been obsolete since, what, 1640?_

Longer than that. The sieve of Eratosthenes is attributed to Eratosthenes, who
lived from 276 BC to 195 BC.

~~~
calpaterson
Hah, this exact thing occurred to me lying in bed last night :)

------
ibdknox
I commented with a much better version of your clojure code. I'm still not
convinced that this is the best way to calculate primes though. Moreover, I
could imagine coming up with a better implementation that uses a lazy seq to
just calculate the next prime when it is needed. Here's the code again:

    
    
        (defn prime? [n]
         (if (even? n) 
          false
          (let [root-plus-one (inc (int (Math/sqrt n)))]
           (every? #(> (mod n %) 0) (range 3 root-plus-one 2)))))
        
        (defn primes [n]
         (conj (filter prime? (range 3 n)) 2))
    

As far as I can tell this is also faster on my machine, but as others suggest,
I don't know that this is a particularly valuable benchmark.

------
calpaterson
Trial division (your algorithm) _is_ linear time, there exist better than
linear time algorithms for this, and they're pretty easy to understand (look
for Solovay-Strassen on wikipedia for a simple one).

Furthermore, this isn't a great test. For one, you're specifically testing a
performance profile that the JVM does not bother to optimise for (programs
that run for less than about 20 seconds). For two, number speeds aren't a
great measure - the issues with autoboxing (that I think Clojure does - I'm
not a user) and whether the implementation is simply calling libgmp (maybe V8
is? Seems sensible to expect that it would - but I am also not a user of
javascript) kind of predecide the outcome.

------
wvl
In addition to the other comments, this is not how you would implement the
code in node. Since node is single threaded, and the isPrime function is not
asynchronous in any way, there is no point to writing it as if it were.
Simplifying it shows it running in 2/3 the time.

<https://gist.github.com/908957>

