Ispirato dalla risposta a this SO question ho preso il codice per controllare un ciclo imperativo contro la ricorsione in coda:bytecode lento con la ricorsione in coda
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());
Per bytecode e codice nativo i risultati sono
[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
La domanda è: qual è la ragione della grande differenza tra 20 e 12 secondi di esecuzione?
Modifica, mia conclusione:
Una chiamata di funzione apply
(nel codice byte) prevede un controllo pila dimensioni, possibile allargamento pila, e un controllo per i segnali. Per le massime prestazioni, il compilatore del codice nativo fornirà.
(Nota a margine:. Chiedere qui su SO, perché è search engine friendly)
opt in ocamlopt sta per ottimizzato. Il compilatore Bytecode esegue meno ottimizzazioni, in quanto non è mai stato il suo scopo. Sebbene molte ottimizzazioni siano ancora fatte. E, per esempio, sulla versione corrente del compilatore (4.03) la differenza è di circa il 10% (9.3 vs 8.3 secondi). – ivg