Ich habe immer geglaubt, dass GHCJS aus naheliegenden Gründen im Vergleich zu manuell geschriebenem und optimiertem Code sehr langsame JavaScript-Programme erzeugte. Als ich damit experimentierte, bemerkte ich, dass es nicht so schlimm war, wie ich es erwartet hatte. Ich beschloss, eine Reihe kleiner Benchmarks zu machen, um die wahre Leistung zu verstehen, und diese überraschte mich besonders. Das Programm füllt einfach ein Array mit "1" und summiert sie.Wie kann dieses Haskell-Programm, kompiliert zu JavaScript, schneller sein als JavaScript selbst?
Haskell:
import Data.Array.Repa
len = 1024*1024*64
arr = fromFunction (Z :. len) (const 1) :: Array D DIM1 Float
main = sumAllP arr >>= print
JavaScript:
var len = 1024*1024*64
var arr = [];
var sum = 0;
for (var i=0; i<len; ++i)
arr[i] = 1;
for (var i=0; i<len; ++i)
sum += arr[i];
console.log(sum);
Und eine grobe Benchmark:
apple1$ ghcjs -O2 bench_fill.hs -funfolding-use-threshold10000 -funfolding-keeness-factor1000 -o bench_fill.js; time node bench_fill.js/all.js
Linking bench_fill.js (Main)
6.7108864e7
real 0m1.543s
user 0m1.512s
sys 0m0.033s
apple1$ time node benchfill.js
67108864
real 0m1.764s
user 0m1.173s
sys 0m0.583s
Wie können die GHCJS schneller laufen als eine schlanke, saubere nativen for-Schleife? Das sollte nicht möglich sein, wenn man bedenkt, wie viele Felder der generierte Code enthalten sollte.
Sind Sie sicher, dass der Haskell-Compiler den Code zum Drucken des Endergebnisses nicht optimiert? In jedem Fall müssen wir wahrscheinlich den generierten Code sehen, um herauszufinden, warum er schneller ist. – JJJ
Geben Sie bitte die Ausgabe .js von ghcjs ein. So beantwortet man die Frage. –
[This] (https://gist.github.com/viclib/3023b1c44daf7f33ede4) ist die Ausgabe js. [This] (https://gist.github.com/viclib/9108f02fb1655cdc0787) auch, außer dass das gesamte Array nach dem Drucken der Summe gedruckt wird, um sicherzustellen, dass es gefüllt ist. – MaiaVictor