Ostatnio natrafiłem na materiał wideo porównujący kolekcje w
językach Java, Scala i z użyciem biblioteki przygotowanej przez
developerów firmy Goldman Sachs. Z ciekawości utowrzyłem podobny
kod w Clojure by porównać wyniki. I muszę powiedzieć, że są
trochę zaskakujące.
W materiale tym porównywana była wydajność kolekcji dla 1
miliona elementów. Postanowiłem utrudnić trochę i dodać 1 zero.
Wyniki są podyktowane cechami mojego PC, na innych komputerach będą
się różnić, być może znacznie.
Tutaj źródło:
http://www.infoq.com/presentations/java-streams-scala-parallel-collections
Java:
List<Long> a;
List<Long> b;
b = LongStream.range(0, 10_000_000)
.boxed()
.collect(Collectors.toList());
a = b.parallelStream()
.filter(e -> e % 10_000 != 0)
.map(e -> String.valueOf(e))
.map(e -> Long.valueOf(e))
.filter(e -> (e + 1) % 10_000 != 0)
.collect(Collectors.toList());
Czas wykonania ~3.8 sekundy po 30 iteracjach.
Clojure:
- funkcje wyciągnięte na zewnątrz dla zwiększenia czytelności
(require
'[clojure.core.reducers :as r])
(defn not10k [^Long x] (not= 0
(rem x 10000)))
(defn not10k1 [^Long x] (not=
0 (rem (inc x) 10000)))
(defn toString [^Long x]
(java.lang.String/valueOf x))
(defn toLong [^String x]
(java.lang.Long/valueOf x))
(def a (vec (range 10000000)))
(def kompozycja (comp
(r/filter not10k1)
(r/map
toLong)
(r/map
toString)
(r/filter
not10k)))
(into [] (kompozycja a)) ;
czas mierzony tutaj
Czas wykonania ~4.7 sekundy. Po 30 iteracjach. Java tylko ok. 24% szybsza. Całkiem nieźle.
Edit:
Aby zwiekszyć wydajność kodu Clojure (prędkość ta sama jak dla Java) trzeba uzyć zwykłej tablicy typu long dla kolekcji wejściowej, więc:
(def a (vec (range 10000000)))
zamienić na:
(def a (long-array (range 10000000)))
Jako ciekawostka, kod w języku Smalltalk (Pharo 3.0):
aStream := (ReadStream on: (1 to: 10000000)) contents readStream.
Time millisecondsToRun: [
bStream := Array new writeStream.
not10k := [ :x | (x rem: 10000) ~= 0 ].
not10k1 := [ :x | (x + 1 rem: 10000) ~= 0 ].
[ ( x := aStream next) notNil ]
whileTrue: [
((not10k value: x) and:
(not10k1 value: (x asString) asNumber))
ifTrue: [ bStream nextPut: x ]].
b := bStream contents.]
~23 sekundy.
Łatwy sposób na zwiększenie wydajności, muszę bardziej przyjrzeć się temu językowi. Coraz lepiej mi to idzie muszę przyznać. Tu też firma https://ermlab.com może was zainteresować jeżeli szukacie specjalistów od tworzenia aplikacji
OdpowiedzUsuń