Ich habe ein ClojureScript-Programm, das hauptsächlich mathematische Berechnungen für Sammlungen durchführt. Es wurde in idiomatischen, Host-unabhängigen Clojure entwickelt, so dass es leicht ist, es zu benchmarken. Zu meiner Überraschung (und im Gegensatz zu dem, was die Antworten zu vorschlagen würden, was schneller ist , Clojure oder ClojureScript (und warum)? ), der gleiche Code in ClojureScript läuft 5-10 mal langsamer als sein Clojure-Äquivalent.
Hier ist was ich getan habe. Ich habe ein lein repl
und einen Browser repl in Ссылка geöffnet. Dann habe ich diese Schnipsel in beiden REPLs ausprobiert.
Dann habe ich eine JavaScript-Konsole im Browser repl geöffnet und eine minimalistische Benchmark-Funktion geschrieben,
%Vor%Zurück zum Browser REPL:
%Vor%Dann versuche sowohl die native Javascript-Multiplikation als auch die Clojurescript-Variante in der JavaScript-Konsole.
%Vor%Was ich gefunden habe
Nun ist meine Frage, wie kann ich die Leistung meines ClojureScript-Programms verbessern?
Es gibt einige Ansätze, die ich bisher in Betracht gezogen habe
(aget js/v 0)
JavaScript hat explizite Rückgabe, also
%Vor%tut nichts; Sie sollten einen Benchmark erstellen
%Vor%stattdessen. Dies ist genau das, was die ClojureScript-Version kompiliert, so dass es keinen Unterschied gibt (in ClojureScript werden grundlegende arithmetische Funktionen bei der Verwendung nicht höherer Ordnung als reguläre operatorbasierte JavaScript-Ausdrücke eingezeichnet).
Jetzt ist Clojure definitiv schneller als ClojureScript. Ein Teil des Grundes ist, dass Clojure noch sorgfältiger abgestimmt ist als ClojureScript, obwohl sich ClojureScript in dieser Abteilung ziemlich schnell verbessert. Ein anderer Teil ist, dass Clojure ein reiferes JIT hat, um davon zu profitieren (die modernen JS-Engines, insbesondere V8, sind ziemlich gut, aber noch nicht ganz HotSpot-Klasse).
Die Größe des Unterschieds ist jedoch etwas schwierig zu messen; Die Tatsache, dass JITs involviert sind, bedeutet, dass eine Schleife mit einem Körper, der frei von irgendwelchen Nebenwirkungen ist, wie der in der Frage, wahrscheinlich weg optimiert wird, möglicherweise sogar beim ersten Durchlauf (durch den Einsatz eines On-Stack-Ersatzes) , benutzt von HotSpot und Ich denke auch V8 - ich müsste das allerdings überprüfen). Also besser, Benchmarks wie
%Vor% ( longs
call, um Reflektionen in Clojure zu vermeiden; könnte auch ^longs
thin verwenden).
Schließlich ist es in Clojure und ClojureScript sicher der Fall, dass es für bestimmte Arten von besonders leistungsempfindlichem Code am besten ist, native Arrays und dergleichen zu verwenden. Glücklicherweise gibt es dafür kein Problem: Auf der ClojureScript-Seite haben Sie array
, js-obj
, aget
, aset
, make-array
, Sie können :mutable
Metadaten für Felder in% co_de verwenden %, um deftype
sie in Methodenkörpern usw. zu finden.
ClojureScript math ist JavaScript-Mathematik. Ja, wenn die Leistung von entscheidender Bedeutung ist, verwenden Sie JavaScript-Arrays und die bereitgestellten Low-Level-Operatoren, diese garantieren, wo immer möglich, optimalen Code (d. H. Keine Verwendung höherer Ordnung). Die ClojureScript persistenten Datenstrukturen sind folgendermaßen geschrieben: Array-Mutation, Arithmetik, Bit-Twiddling.
Ich habe ein kleines Beispiel für effizientes ClojureScript - Ссылка die Sie als Leitfaden nützlich finden könnten.
Tags und Links clojure performance clojurescript