2016-06-22 14 views
24

Hier mein Benchmark-Code ist:Warum ist Array.slice so (schockierend!) Langsam?

def bm(duration: Long)(f: => Unit)={ 
    val end = System.currentTimeMillis + duration 
    var count = 0 
    while(System.currentTimeMillis < end) { f; count += 1 } 
    count 
} 

val array = new scala.util.Random().alphanumeric.take(1000).toArray 

(1 to 20).map { _ => bm(1000) { array.slice(100,200) } }.sum/20 

dies mehrmals Rennen, ich Zahlen konsequent im Baseballstadion von etwa 1,5 Millionen Scheiben pro Sekunde. Zwischen 1.4 und 1.6.

Nun, ich dies tun:

implicit class FastSlicing(val a: Array[Char]) extends AnyVal { 
    def fastSlice(from: Int, until: Int) = Arrays.copyOfRange(a, from, until) 
} 
(1 to 20).map { _ => bm(1000) { array.fastSlice(100,200) } }.sum/20 

Und das Ergebnis I erhalten zwischen 16 und 18 Millionen Scheiben pro Sekunde. Dies ist mehr als 10 mal schneller.

Jetzt kenne ich alle üblichen Überlegungen über die Kompromisse, die scala macht, um funktionale Idiome und Typ Sicherheit manchmal auf Kosten der Leistung zu bieten ... Aber in diesem Fall, denke ich, dass sie alle nicht beantworten ein einfache Frage: warum ist ArrayOps.slice nicht auf diese Weise implementiert ??? Mir ist klar, dass es mehrere identische Implementierungen geben würde, wegen der Art, wie Java mit primitiven Arrays umgeht, aber das ist höchstens ein kleiner Ärger, nicht wirklich ein Deal-Breaker-Problem, um einen 10-fachen Performance-Hit zu rechtfertigen.

Die .slice ist nur ein Beispiel, die meisten anderen Array-Ops scheinen auch unter dem gleichen Problem zu leiden. Warum muss es so sein?

aktualisieren jetzt, hier ist etwas, das ich noch schockierender finden:

val seq = new scala.util.Random().alphanumeric.take(1000).toIndexedSeq 
(1 to 20).map { _ => bm(1000) { seq.slice(100,200) } }.sum/20 

Dies gilt etwa 5-6000000 Scheiben für mich pro Sekunde. Aber das:

import scala.collections.JavaConversions._ 
(1 to 20).map { _ => bm(1000) { seq.subList(100,200) } }.sum/20 

tut zwischen 12 und 15 Millionen! Zugegeben, dies ist keine Grössenordnung, wie im Falle der Arrays, aber (1) es gibt keine spezielle Behandlung von Primitiven, die hier involviert sind, also wäre es völlig trivial, einfach Java Tools zu implementieren und (2) Sammlung ist unveränderlich ... Wie schwer kann es sein, einen Verweis auf eine Reihe von Indizes ???

+1

Haben Sie schon den Code dahinter gesehen? – Vale

+0

@Vale ja, ich habe. Hast du die Frage gelesen? ;) – Dima

+1

Ich habe, aber kann nicht die Linie finden, wo Sie sagen, dass Sie getan haben. Ich bin vielleicht schlecht im Leseverstehen. – Vale

Antwort