Zainspirowany odpowiedzi this SO question wziąłem kod, aby sprawdzić się imperatyw pętlę przed ogonowej rekursji:powolny kod bajtowy z ogona rekurencji
let rec nothingfunc i =
match i with
| 1000000000 -> 1
| _ -> nothingfunc (i+1)
let nothingloop1() =
let i = ref 0 in
while !i < 1000000000 do incr i done;
1
let timeit f v =
let t1 = Unix.gettimeofday() in
let _ = f v in
let t2 = Unix.gettimeofday() in
t2 -. t1
let() =
Printf.printf "recursive function: %g s\n%!" (timeit nothingfunc 0);
Printf.printf "while loop with ref counter buitin incr: %g s\n%!" (timeit nothingloop1());
Dla kodu bajtowego i kodu natywnego wyniki są
[email protected]:~> ./bench_loop
recursive function: 20.7656 s
while loop with ref counter buitin incr: 12.0642 s
[email protected]:~> ./bench_loop.opt
recursive function: 0.755594 s
while loop with ref counter buitin incr: 0.753947 s
Pytanie brzmi: jaki jest powód dużej różnicy 20 do 12 sekund czasu realizacji?
Edit, moja konkluzja:
Wywołanie funkcji apply
(w kodu bajtowego) obejmuje sprawdzenie stosu rozmiar, ewentualnego rozszerzenia stosu i czek na sygnałach. Aby uzyskać maksymalną wydajność, dostarczony zostanie kompilator natywnego kodu.
(uwaga Side. Prosząc tutaj na SO, ponieważ jest przyjazny dla wyszukiwarek)
opt w ocamlopt oznacza zoptymalizowany. Kompilator Bytecode wykonuje mniej optymalizacji, ponieważ nigdy nie był jego celem. Chociaż wiele optymalizacji nadal jest wykonywanych. I na przykład na aktualnej wersji kompilatora (4.03) różnica wynosi około 10% (9,3 vs 8,3 sekundy). – ivg