Warum Python und Ruby so langsam, während das Lisp-Implementierungen sind schnell?

Finde ich, dass einfache Dinge, wie Funktionsaufrufe und Schleifen, und Schleifen Inkrementieren einen Zähler nehmen weit mehr Zeit in Python und Ruby als im Chicken Scheme, Racket, oder SBCL.

Warum ist das so? Oft höre ich Leute sagen, dass die Langsamkeit ist ein Preis, den Sie bezahlen für dynamische Sprachen, aber Lisps sind sehr dynamisch und sind nicht lächerlich langsam (Sie sind in der Regel weniger als 5 mal langsamer als C, Ruby und Python kann in den zweistelligen Bereich). Außerdem Lisp-Stil verwendet Rekursion, und nicht immer tail-Rekursion, einer viel, der stack ist eine verknüpfte Liste von Fortsetzungen in den heap, etc, die scheinen, zu sein die Dinge machen sollten Lisp langsamer als der Imperativ-Stil, Python und Ruby.

Schläger und SBCL sind JITted, aber Chicken Scheme ist entweder statisch kompiliert werden, oder verwendet ein nicht-optimierender interpreter, beide sollten schlecht geeignet, um dynamische Sprachen und langsam. Doch auch mit der naiven csi Dolmetscher für Hähnchen-System (das gar nicht tun bytecode-Kompilierung!), Bekomme ich Geschwindigkeiten von weit über Python und Ruby.

Warum genau sind Python und Ruby so lächerlich langsam im Vergleich zu den ähnlich dynamische Lisps? Ist es, weil Sie Objekt-orientiert und brauchen riesige vtables und geben heirarchies?

Beispiel: Fakultät-Funktion. Python:

def factorial(n):
    if n == 0:
        return 1
    else:
    return n*factorial(n-1)

for x in xrange(10000000):
    i = factorial(10)

Schläger:

#lang racket

(define (factorial n)
  (cond
   [(zero? n) 1]
   [else (* n (factorial (sub1 n)))]))

(define q 0)

(for ([i 10000000])
  (set! q (factorial 10)))

Timing Resultate:

ithisa@miyasa /scratch> time racket factorial.rkt
racket factorial.rkt  1.00s user 0.03s system 99% cpu 1.032 total
ithisa@miyasa /scratch> time python factorial.py
python factorial.py  13.66s user 0.01s system 100% cpu 13.653 total
  • SBCL nicht eine Verwendung eines JIT. Es ist strengstens AOT.
  • SBCL ist eine REPL-interpreter...mir ist das common lisp n00b immer als Dolmetscher...
  • SBCL verwendet einen compiler. Immer und überall. In der REPL auch. SBCL verwendet keinen interpreter, standardmäßig. Jeden Ausdruck, den Sie eingeben, an der REPL kompiliert wird, bevor er ausgeführt wird.
  • Ja, so REPL ist technisch ein JIT-compiler...
  • Nein. Die REPL ruft einfach nur EVAL, die ruft die native-code-compiler. Der code vollständig kompiliert aus dem source-code in systemeigenen code VOR der Laufzeit. Es ist nur eine inkrementelle compiler, die kompilieren können, den individuellen Ausdruck. Es gibt keine byte code compilation, keine byte-code in systemeigenen code JIT-Kompilierung, keine runtime-Analyse keine code-cache, ... Es ist eine inkrementelle native-code-compiler.
  • Weil die Menschen damit verbracht haben, mit 55 Jahren, die die Lisp-schnell, aber nur bei 20,5 Jahren, die die Ruby schnell. Und weil die Menschen damit verbracht haben, Millionen von Dollar zu machen Lisp schnell.
  • Lisps sind nicht dynamisch, im Vergleich mit der Ente-typisierten OO-Sprachen.
  • In welcher Weise ist Lisp "nicht dynamisch"?
  • Lisp verlassen Sie sich nicht auf dynamische Methode dispatch. Es hat einige polymorphe Funktionen (notorisch, numerische Turm), aber die Mehrheit der call-Ziele sind entscheidbar, im compile-Zeit, im Gegensatz zu Sprachen wie Python, wo jeder Anruf muss entschieden werden, in der runtime.
  • Der Maßstab nicht gerecht wird einem erfahrenen python-Nutzer Ausgabe. Sie würden mit pypy, numba, oder cython, wenn der code nicht schnell genug. Ich habe 18 Sekunden für den code, so sah cython in meinem jupyter notebook. Eine naive version beschleunigt es bis um 4 mal um 5 Sekunden. Eine differenziertere Anwendung reduziert Sie 0,33 Sekunden schneller als lisp und oft nähert sich C. nbviewer.jupyter.org/github/john9631/Jupyter-Notebooks/blob/...

InformationsquelleAutor ithisa | 2013-11-09
Schreibe einen Kommentar