Tout d’abord, je voudrais préciser que ce n’est pas une question langue X-langue-Y qui permet de déterminer laquelle est la meilleure.
J'utilise Java depuis longtemps et j'ai l'intention de continuer à l'utiliser. Parallèlement à cela, j'apprends actuellement Scala avec un grand intérêt: mis à part quelques petites choses qui prennent un certain temps pour s'habituer à mon impression, c'est que je peux vraiment très bien travailler dans cette langue.
Ma question est la suivante: comment les logiciels écrits en Scala se comparent-ils aux logiciels écrits en Java en termes de vitesse d'exécution et de consommation de mémoire? Bien sûr, il est difficile de répondre à cette question en général, mais je m'attendrais à ce que les constructions de niveau supérieur telles que la correspondance de modèle, les fonctions d'ordre supérieur, etc. introduisent une surcharge.
Cependant, mon expérience actuelle à Scala se limite à de petits exemples de moins de 50 lignes de code et je n'ai pas encore effectué de tests de performances. Donc, je n'ai pas de données réelles.
S’il s’avère que Scala a une surcharge en Java, est-il judicieux d’avoir des projets Scala / Java mixtes, dans lesquels on code les parties les plus complexes de Scala et les parties critiques en termes de performance en Java? Est-ce une pratique courante?
EDIT 1
J'ai exécuté un petit test d'évaluation: créez une liste d'entiers, multipliez chaque entier par deux et mettez-la dans une nouvelle liste, imprimez la liste résultante. J'ai écrit une implémentation Java (Java 6) et une implémentation Scala (Scala 2.9). J'ai couru les deux sur Eclipse Indigo sous Ubuntu 10.04.
Les résultats sont comparables: 480 ms pour Java et 493 ms pour Scala (moyenne sur 100 itérations). Voici les extraits que j'ai utilisés.
// 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))
}
Ainsi, dans ce cas, il semble que les frais généraux de Scala (utilisant range, map, lambda) soient vraiment minimes, ce qui n’est pas loin des informations fournies par World Engineer.
Peut-être y a-t-il d'autres constructions Scala qui devraient être utilisées avec précaution car elles sont particulièrement lourdes à exécuter?
EDIT 2
Certains d'entre vous ont fait remarquer que les impressions dans les boucles internes occupent la majeure partie du temps d'exécution. Je les ai supprimés et ai défini la taille des listes sur 100000 au lieu de 20000. La moyenne résultante était de 88 ms pour Java et de 49 ms pour Scala.
la source
Réponses:
Il y a une chose que vous pouvez faire avec concision et efficacité en Java et que vous ne pouvez pas utiliser dans Scala: les énumérations. Pour tout le reste, même pour les constructions lentes dans la bibliothèque de Scala, vous pouvez obtenir des versions efficaces fonctionnant dans Scala.
Donc, pour la plupart, vous n'avez pas besoin d'ajouter Java à votre code. Même pour le code qui utilise l'énumération en Java, il existe souvent une solution adéquate ou bonne dans Scala: je place l'exception sur les énumérations qui ont des méthodes supplémentaires et dont les valeurs de constante int sont utilisées.
En ce qui concerne ce qu'il faut surveiller, voici certaines choses.
Si vous utilisez le modèle enrichir ma bibliothèque, convertissez-le toujours en classe. Par exemple:
Méfiez-vous des méthodes de collecte - car elles sont généralement polymorphes, JVM ne les optimise pas. Vous n'avez pas besoin de les éviter, mais faites attention aux sections critiques. Sachez que
for
Scala est implémenté via des appels de méthodes et des classes anonymes.Si vous utilisez une classe Java, telle que
String
,Array
ou desAnyVal
classes correspondant à des primitives Java, préférez les méthodes fournies par Java lorsque des alternatives existent. Par exemple, utilisezlength
onString
et à laArray
place desize
.Évitez d’utiliser imprudemment les conversions implicites, car vous pouvez vous retrouver à utiliser des conversions par erreur plutôt que de par leur conception.
Étendre les classes au lieu des traits. Par exemple, si vous étendez
Function1
, étendez à laAbstractFunction1
place.Utilisation
-optimise
et spécialisation pour tirer le meilleur parti de Scala.Comprenez ce qui se passe:
javap
votre ami est-il, ainsi que de nombreux drapeaux Scala indiquant ce qui se passe.Les idiomes Scala sont conçus pour améliorer la correction et rendre le code plus concis et facile à gérer. Ils ne sont pas conçus pour la vitesse, donc si vous devez utiliser
null
plutôt queOption
sur un chemin critique, faites-le! Il y a une raison pour laquelle Scala est multi-paradigme.N'oubliez pas que la véritable mesure des performances consiste à exécuter du code. Voir cette question pour un exemple de ce qui peut arriver si vous ignorez cette règle.
la source
Selon le jeu de référence pour un système 32 bits à cœur unique, Scala se situe à une médiane de 80% aussi rapide que Java. Les performances sont approximativement les mêmes pour un ordinateur Quad Core x64. Même l' utilisation de la mémoire et la densité de code sont très similaires dans la plupart des cas. Je dirais, sur la base de ces analyses (plutôt non scientifiques), que vous avez raison d'affirmer que Scala ajoute une surcharge à Java. Cela ne semble pas ajouter des tonnes de frais généraux, donc je suppose que le diagnostic du plus grand nombre d'articles nécessitant une plus grande quantité d'espace / de temps est le plus correct.
la source
Int
,Char
etc. quand il le peut. Les boucles While sont tout aussi efficaces en Scala.Function
classes. Si vous passez un lambda àmap
, la classe anonyme doit être instanciée (et il peut être nécessaire de transmettre certaines sections locales), puis chaque itération entraîne une surcharge supplémentaire d'appels de fonction (avec certains paramètres passés)apply
.scala.util.Random
sont que des wrappers autour de classes JRE équivalentes. L'appel de fonction supplémentaire est légèrement inutile.java.lang.Math.signum(x)
est beaucoup plus direct quex.signum()
, qui convertitRichInt
et retour.la source
réduit le temps de 800 ms à 20 sur mon système.
la source