Znajomy dał mi ten fragment kodu w ClojureDlaczego Clojure jest znacznie szybszy niż Scala w rekurencyjnej funkcji dodawania?
(defn sum [coll acc] (if (empty? coll) acc (recur (rest coll) (+ (first coll) acc))))
(time (sum (range 1 9999999) 0))
i zapytał mnie, jak to taryfy przed podobnym realizacji Scala.
Kod Scala I zostały napisane wygląda następująco:
def from(n: Int): Stream[Int] = Stream.cons(n, from(n+1))
val ints = from(1).take(9999998)
def add(a: Stream[Int], b: Long): Long = {
if (a.isEmpty) b else add(a.tail, b + a.head)
}
val t1 = System.currentTimeMillis()
println(add(ints, 0))
val t2 = System.currentTimeMillis()
println((t2 - t1).asInstanceOf[Float] + " msecs")
Konkluzja jest: kodu w Clojure działa w około 1,8 sekundy na moim komputerze i używa mniej niż 5 MB sterty, kod w Scala działa w około 12 sekund, a 512 MB sterty nie wystarcza (kończy obliczenia, jeśli ustawię stertę na 1GB).
Więc zastanawiam się, dlaczego Clojure jest o wiele szybszy i szczuplejszy w tym konkretnym przypadku? Czy masz implementację Scala, która ma podobne zachowanie pod względem szybkości i wykorzystania pamięci?
Proszę powstrzymać się od uwag religijnych, moje zainteresowanie polega przede wszystkim na tym, aby dowiedzieć się przede wszystkim, co powoduje, że clojure jest tak szybki w tym przypadku i czy istnieje szybsza implementacja algo w scala. Dzięki.
To prawda, że zwiększa to zużycie pamięci. A co ze zwiększonym czasem obliczeń? –
Zwiększony czas obliczeń jest poświęcony na przydzielanie pamięci i bezowocne próby jej usunięcia. –
Jeśli używałeś basenu z recyklingowanych przedmiotów, czy to dużo przyspieszy? JVM obsługuje krótkotrwałe obiekty sterty z wydajnością bardziej przypominającą stos, więc zaskoczyłoby mnie, gdyby GC naprawdę zajmowało dużo czasu. –