Zunächst möchte ich klarstellen, dass es sich nicht um eine Frage von Sprache X gegen Sprache Y handelt, um festzustellen, welche Frage besser ist.
Ich habe Java für eine lange Zeit benutzt und ich beabsichtige, es weiter zu benutzen. Parallel dazu lerne ich gerade Scala mit großem Interesse: Abgesehen von Kleinigkeiten, an die ich mich erst gewöhnen muss, kann ich in dieser Sprache wirklich sehr gut arbeiten.
Meine Frage ist: Wie verhält sich in Scala geschriebene Software in Bezug auf Ausführungsgeschwindigkeit und Speicherverbrauch zu in Java geschriebener Software? Natürlich ist diese Frage im Allgemeinen schwierig zu beantworten, aber ich würde erwarten, dass Konstrukte höherer Ebenen wie Mustervergleiche, Funktionen höherer Ordnung usw. einen gewissen Overhead verursachen.
Meine derzeitigen Erfahrungen mit Scala beschränken sich jedoch auf kleine Beispiele mit weniger als 50 Codezeilen, und ich habe bisher keine Benchmarks durchgeführt. Ich habe also keine wirklichen Daten.
Wenn es stellte sich heraus , dass Scala hat einige Kopf WRT Java, macht es Sinn gemischte Scala / Java - Projekte zu haben , machen, wo man Codes die komplexeren Teile in Scala und die erfolgskritischen Teile in Java? Ist das eine gängige Praxis?
EDIT 1
Ich habe einen kleinen Benchmark durchgeführt: Eine Liste mit ganzen Zahlen erstellen, jede ganze Zahl mit zwei multiplizieren und in eine neue Liste einfügen. Die resultierende Liste ausdrucken. Ich habe eine Java-Implementierung (Java 6) und eine Scala-Implementierung (Scala 2.9) geschrieben. Ich habe beide auf Eclipse Indigo unter Ubuntu 10.04 ausgeführt.
Die Ergebnisse sind vergleichbar: 480 ms für Java und 493 ms für Scala (gemittelt über 100 Iterationen). Hier sind die Schnipsel, die ich verwendet habe.
// Java
public static void main(String[] args)
{
long total = 0;
final int maxCount = 100;
for (int count = 0; count < maxCount; count++)
{
final long t1 = System.currentTimeMillis();
final int max = 20000;
final List<Integer> list = new ArrayList<Integer>();
for (int index = 1; index <= max; index++)
{
list.add(index);
}
final List<Integer> doub = new ArrayList<Integer>();
for (Integer value : list)
{
doub.add(value * 2);
}
for (Integer value : doub)
{
System.out.println(value);
}
final long t2 = System.currentTimeMillis();
System.out.println("Elapsed milliseconds: " + (t2 - t1));
total += t2 - t1;
}
System.out.println("Average milliseconds: " + (total / maxCount));
}
// Scala
def main(args: Array[String])
{
var total: Long = 0
val maxCount = 100
for (i <- 1 to maxCount)
{
val t1 = System.currentTimeMillis()
val list = (1 to 20000) toList
val doub = list map { n: Int => 2 * n }
doub foreach ( println )
val t2 = System.currentTimeMillis()
println("Elapsed milliseconds: " + (t2 - t1))
total = total + (t2 - t1)
}
println("Average milliseconds: " + (total / maxCount))
}
In diesem Fall scheint der Scala-Overhead (mit Bereich, Karte, Lambda) wirklich minimal zu sein, was nicht weit von den Informationen von World Engineer entfernt ist.
Vielleicht gibt es andere Scala-Konstrukte, die mit Vorsicht verwendet werden sollten, weil sie besonders schwer auszuführen sind?
BEARBEITEN 2
Einige von Ihnen haben darauf hingewiesen, dass die Ausdrucke in den inneren Schleifen die meiste Ausführungszeit in Anspruch nehmen. Ich habe sie entfernt und die Größe der Listen auf 100000 anstatt auf 20000 eingestellt. Der resultierende Durchschnitt betrug 88 ms für Java und 49 ms für Scala.
quelle
Antworten:
Es gibt eine Sache, die Sie in Java präzise und effizient ausführen können, die Sie in Scala nicht können: Aufzählungen. Für alles andere, auch für Konstrukte, die in der Bibliothek von Scala langsam sind, können Sie effiziente Versionen in Scala erstellen.
Daher müssen Sie Ihrem Code zum größten Teil kein Java hinzufügen. Selbst für Code, der in Java eine Aufzählung verwendet, gibt es in Scala häufig eine adäquate oder gute Lösung - ich setze die Ausnahme auf Aufzählungen, die über zusätzliche Methoden verfügen und deren int-konstante Werte verwendet werden.
Hier sind einige Dinge, auf die Sie achten sollten.
Wenn Sie das Muster Meine Bibliothek anreichern verwenden, konvertieren Sie immer in eine Klasse. Zum Beispiel:
Seien Sie vorsichtig mit Erfassungsmethoden - da diese zum größten Teil polymorph sind, optimiert JVM sie nicht. Sie brauchen sie nicht zu meiden, aber achten Sie auf kritische Abschnitte. Beachten Sie, dass
for
in Scala Methodenaufrufe und anonyme Klassen implementiert werden.Bei Verwendung einer Java - Klasse, wie
String
,Array
oderAnyVal
Klassen , die entsprechen Java Primitive, bevorzugen die Methoden von Java zur Verfügung gestellt , wenn es Alternativen gibt. Verwenden Sie beispielsweiselength
onString
undArray
anstelle vonsize
.Vermeiden Sie die unachtsame Verwendung impliziter Conversions, da Sie möglicherweise versehentlich Conversions anstelle von beabsichtigten Conversions verwenden.
Erweitern Sie Klassen anstelle von Merkmalen. Wenn Sie beispielsweise erweitern
Function1
, erweitern SieAbstractFunction1
stattdessen.Verwendung
-optimise
und Spezialisierung, um den größten Teil von Scala zu erhalten.Verstehe, was passiert:
javap
Ist dein Freund, und so sind auch ein paar Scala-Flaggen, die zeigen, was los ist.Scala-Redewendungen sollen die Korrektheit verbessern und den Code übersichtlicher und wartbarer machen. Sie sind nicht auf Geschwindigkeit ausgelegt, so dass , wenn Sie verwenden müssen ,
null
stattOption
in einem kritischen Pfad, tun! Es gibt einen Grund, warum Scala ein Multiparadigma ist.Denken Sie daran, dass das wahre Maß für die Leistung die Ausführung von Code ist. In dieser Frage finden Sie ein Beispiel dafür, was passieren kann, wenn Sie diese Regel ignorieren.
quelle
Nach dem Benchmarks-Spiel für ein 32-Bit-System mit einem Kern ist Scala im Median 80% so schnell wie Java. Die Leistung ist für einen Quad Core x64-Computer ungefähr gleich. Sogar die Speichernutzung und die Codedichte sind in den meisten Fällen sehr ähnlich. Ich würde auf der Grundlage dieser (eher unwissenschaftlichen) Analysen sagen, dass Sie zu Recht behaupten, dass Scala Java etwas Aufwand hinzufügt. Es scheint nicht viel Overhead hinzuzufügen, daher würde ich vermuten, dass die Diagnose von Artikeln höherer Ordnung, die mehr Platz / Zeit beanspruchen, die richtigste ist.
quelle
Int
,Char
usw. , wenn er kann. While-Schleifen sind in Scala genauso effizient.Function
Klassen kompiliert werden. Wenn Sie ein Lambda an übergebenmap
, muss die anonyme Klasse instanziiert werden (und einige lokale Klassen müssen möglicherweise übergeben werden), und dann hat jede Iteration zusätzlichen Funktionsaufruf-Overhead (mit einigen Parameterübergaben) von denapply
Aufrufen.scala.util.Random
sind nur Wrapper um äquivalente JRE-Klassen. Der zusätzliche Funktionsaufruf ist etwas verschwenderisch.java.lang.Math.signum(x)
ist viel direkter alsx.signum()
, was zuRichInt
und zurück konvertiert .quelle
reduziert die Zeit von 800 ms auf 20 auf meinem System.
quelle