вторник, 30 ноября 2010 г.

Скорость вычислений на F#

Недавно задумался над скоростью вычислений в F#, а вернее о том, стоит ли заморачиваться использую lazy() и seq. Поверхностные тесты seq показывают, что seq лучше для вычислений чем list:



> Seq.sum (seq{ for i in 1.0 .. 50.0 -> 1.0/(i*i*i) });;
Real: 00:00:00.001, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0
val it : float = 1.201860863
> List.sum [ for i in 1.0 .. 50.0 -> 1.0/(i*i*i) ];;
Real: 00:00:00.002, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0
val it : float = 1.201860863
> ;;
> ;;
> ;;
> Seq.sum (seq{ for i in 1.0 .. 50000.0 -> 1.0/(i*i*i) });;
Real: 00:00:00.008, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0
val it : float = 1.202056903
> List.sum [ for i in 1.0 .. 50000.0 -> 1.0/(i*i*i) ];;
Real: 00:00:00.013, CPU: 00:00:00.015, GC gen0: 1, gen1: 0, gen2: 0
val it : float = 1.202056903
> List.sum [ for i in 1.0 .. 5000000.0 -> 1.0/(i*i*i) ];;
Real: 00:00:02.589, CPU: 00:00:02.870, GC gen0: 38, gen1: 26, gen2: 3
val it : float = 1.202056903
> Seq.sum (seq{ for i in 1.0 .. 5000000.0 -> 1.0/(i*i*i) });;
Real: 00:00:00.800, CPU: 00:00:00.795, GC gen0: 0, gen1: 0, gen2: 0
val it : float = 1.202056903

Причём чем больше эл-тов требуется вычислить, тем менее производительней становиться список, т.к. ему требуется подчищать за собой память оч. активно.


п.с. если использовать честный fold, то seq несколько замедляется, но всёравно в 2 раза быстрее списка:

> Seq.fold (fun acc e -> acc + e) 0.0 (seq{ for i in 1.0 .. 5000000.0 -> 1.0/(i*i*i) });;
Real: 00:00:01.125, CPU: 00:00:01.092, GC gen0: 0, gen1: 0, gen2: 0
val it : float = 1.202056903
> List.fold (fun acc e -> acc + e) 0.0 ([ for i in 1.0 .. 5000000.0 -> 1.0/(i*i*i) ]);;
Real: 00:00:02.716, CPU: 00:00:02.776, GC gen0: 35, gen1: 28, gen2: 1
val it : float = 1.202056903

правда стоит заметить, что для seq использование fold увеличило требуемое время на 0.3 сек, в то время когда для списка всего на 0.127 сек