In one of my previous posts I compared Clojure with Python by implementing two identical versions of a program to solve problem 34 from Project Euler in both languages. My results showed that Clojure was able to be three times faster than Python when type hinting (TH) was enabled (even without TH Clojure was however faster than Python). My idea was then that any type-hinted (semi-)interpreted language like Clojure would have reached the same speed.
In the last month I have run some other tests, and I must say that my idea has changed. A number of Scheme/Common LISP implementation have proven to be even faster than Clojure, and this without type hints!
I am not going to provide my Common LISP and Scheme programs, as they are trivial conversions of the Clojure program I presented before. These are the compilers/interpreters I used to write and run my test programs:
Name | Version | Language | Timing |
---|---|---|---|
Ikarus | 0.4 RC1 | Scheme | 14 |
Larceny | 0.97 | Scheme | 15 |
Bigloo | 3.5a | Scheme | 16 |
Steel Bank CL | 1.0.44 | Common LISP | 17 |
MZScheme (DrRacket) | 5.0.1 | Scheme | 17 |
STklos | 1.0 | Scheme | 43 |
CMU CL | 20b | Common LISP | 47 |
Clozure CL | 1.5 | Common LISP | 62 |
Chicken | 4.6.3 | Scheme | 93 |
Chicken | 4.4.0 | Scheme | 102 |
CLISP | 2.49 | Common LISP | 106 |
CPython (fast) | 2.6.6 | Python | 135 |
CPython | 2.6.6 | Python | 145 |
ECL | 10.4.1 | Common LISP | 169 |
The "CPython (fast)" entry is a rewrite of my original Python program
so that the body of solution
does not call other Python functions:
sum ([num for num in xrange (10, max_n) if num == sum ([FAST_FACT[digit] for digit in [int(x) for x in list (str (num))]])])
A few notes about these results:
- There is more than one order of magnitude between the slowest implementation (ECL) and the fastest (Ikarus Scheme);
- Compilers without TH (e.g. Ikarus, Larceny, Bigloo, SBCL) run much faster than Clojure with TH. I was really surprised!
- Avoiding function calls make CPython faster, but not much faster;
- The fastest program runs using Ikarus, a compiler in alpha stage that has been put on hiatus after the author (apparently) changed his job. What a pity! (Note however that Marco Maggi has forked Ikarus into Vicare, which seems to be actively developed.)
- While I had to change my Scheme program in order to make it runnable under various Scheme compilers/interpreters (nothing sensational, just one or two lines at the beginning), my Common LISP program ran unchanged under SBCL, ECL and CCL. One point for portability to Common LISP!
Here is a barchart of the results (click to zoom):
Update: After a suggestion by Water I included in my benchmarks also CLISP (and corrected the name) and CMU Lisp (which was mentioned in one of the pages at CLISP's site as being faster than CLISP – and indeed it is). In both cases I first compiled the program and then timed the execution of the bytecode. I have also added MZScheme, which I left out in the first version of this post. The table and the chart have been updated accordingly.
One small correction: "CLISP" is not the correct abbreviation for "Common Lisp". It is more common to just use CL. CLISP itself, on the other side, is one of the more popular implementations of Common Lisp (see http://www.gnu.org/software/clisp/), which would have been nice to see in your benchmark.
ReplyDelete