scala vs java, performance et mémoire? [fermé]


Je tiens à me pencher sur Scala, et j'ai une question de base à laquelle je ne peux pas trouver de réponse: en général, existe-t-il une différence de performances et d'utilisation de la mémoire entre Scala et Java?

Author: JohnSmith, 2011-05-05

8 answers

Scala rend très facile d'utiliser d'énormes quantités de mémoire sans s'en rendre compte. Ceci est généralement très puissant, mais peut parfois être ennuyeux. Par exemple, supposons que vous ayez un tableau de chaînes (appelé array) et une carte de ces chaînes vers des fichiers (appelé mapping). Supposons que vous souhaitiez obtenir tous les fichiers qui se trouvent dans la carte et proviennent de chaînes de longueur supérieure à deux. En Java, vous pourriez

int n = 0;
for (String s: array) {
  if (s.length > 2 && mapping.containsKey(s)) n++;
}
String[] bigEnough = new String[n];
n = 0;
for (String s: array) {
  if (s.length <= 2) continue;
  bigEnough[n++] = map.get(s);
}

Ouf! Labeur. Dans Scala, la façon la plus compacte de faire la même chose est:

val bigEnough = array.filter(_.length > 2).flatMap(mapping.get)

Facile! Mais, à moins que vous ne connaissiez assez bien le fonctionnement des collections, ce que vous ne réalisez peut-être pas, c'est que cette façon de faire a créé un tableau intermédiaire supplémentaire (avec filter) et un objet supplémentaire pour chaque élément du tableau (avec mapping.get, qui renvoie une option). Il crée également deux objets de fonction (un pour le filtre et un pour le flatMap), bien que ce soit rarement un problème majeur car les objets de fonction sont petits.

Donc, fondamentalement, la mémoire l'utilisation est, à un niveau primitif, le même. Mais les bibliothèques de Scala ont de nombreuses méthodes puissantes qui vous permettent de créer très facilement un nombre énorme d'objets (généralement de courte durée). Le garbage collector est généralement assez bon avec ce genre de déchets, mais si vous ignorez complètement quelle mémoire est utilisée, vous aurez probablement des problèmes plus tôt dans Scala que Java.

Notez que le code Scala du jeu de référence des langages informatiques est écrit dans un style plutôt Java afin de obtenez des performances de type Java, et a donc une utilisation de la mémoire de type Java. Vous pouvez le faire dans Scala: si vous écrivez votre code pour ressembler à du code Java haute performance, ce sera du code Scala haute performance. (Vous pouvez être capable de l'écrire dans un style Scala plus idiomatique et d'obtenir de bonnes performances, mais cela dépend des spécificités.)

Je devrais ajouter que par quantité de temps passé à programmer, mon code Scala est généralement plus rapide{[12] } que mon code Java car dans Scala, je peux obtenir le les pièces fastidieuses non critiques pour les performances sont effectuées avec moins d'effort et passent plus d'attention à optimiser les algorithmes et le code pour les pièces critiques pour les performances.

 245
Author: Rex Kerr, 2011-05-05 17:24:48

Je suis un nouvel utilisateur, donc je ne suis pas en mesure d'ajouter un commentaire à la réponse de Rex Kerr ci-dessus (permettre aux nouveaux utilisateurs de "répondre" mais pas de "commenter" est une règle très étrange btw).

Je me suis inscrit simplement pour répondre à l'insinuation "ouf, Java est si verbeux et si dur" de la réponse populaire de Rex ci-dessus. Bien que vous puissiez bien sûr écrire du code Scala plus concis, l'exemple Java donné est clairement gonflé. La plupart des développeurs Java codifieraient quelque chose comme ceci:

List<String> bigEnough = new ArrayList<String>();
for(String s : array) {
  if(s.length() > 2 && mapping.get(s) != null) {
    bigEnough.add(mapping.get(s));
  }
}

Et bien sûr, si nous allons pour prétendre qu'Eclipse ne fait pas la plupart de la frappe réelle pour vous et que chaque caractère enregistré fait vraiment de vous un meilleur programmeur, alors vous pouvez coder ceci:

List b=new ArrayList();
for(String s:array)
  if(s.length()>2 && mapping.get(s) != null) b.add(mapping.get(s));

Maintenant, non seulement j'ai économisé le temps qu'il m'a fallu pour taper des noms de variables complets et des accolades (me libérant de passer 5 secondes de plus à penser à des pensées algorithmiques profondes), mais je peux également entrer mon code dans des concours d'obscurcissement et potentiellement gagner de l'argent supplémentaire pour les vacances.

 96
Author: Not Sleeping, 2012-01-02 19:03:56

Écrivez votre Scala comme Java, et vous pouvez vous attendre à ce que du bytecode presque identique soit émis - avec des métriques presque identiques.

Écrivez-le plus "idiomatiquement", avec des objets immuables et des fonctions d'ordre supérieur, et ce sera un peu plus lent et un peu plus grand. La seule exception à cette règle empirique est lors de l'utilisation d'objets génériques dans lesquels les paramètres de type utilisent l'annotation @specialised, cela créera un bytecode encore plus grand qui peut dépasser les performances de Java en évitant boxing/unboxing.

Il convient également de mentionner le fait que plus de mémoire / moins de vitesse est un compromis inévitable lors de l'écriture de code qui peut être exécuté en parallèle. Le code Scala idiomatique est beaucoup plus déclaratif que le code Java typique, et est souvent à seulement 4 caractères (.par) d'être complètement parallèle.

Donc si

  • Le code Scala prend 1,25 fois plus de temps que le code Java dans un seul thread
  • Il peut être facilement divisé en 4 cœurs (maintenant commun même dans les ordinateurs portables)
  • pour une durée d'exécution parallèle de (1.24 / 4 =) 0.3125 x le Java d'origine

Diriez-vous alors que le code Scala est maintenant comparativement 25% plus lent, ou 3 fois plus rapide?

La bonne réponse dépend exactement de la façon dont vous définissez "performance":)

 63
Author: Kevin Wright, 2011-05-05 17:41:47

Le Langage De L'Ordinateur Repères De Jeu:

Test de vitesse java/scala 1.71 / 2.25

Test de mémoire java / scala 66.55 / 80.81

Donc, ces benchmarks disent que java est 24% plus rapide et que scala utilise 21% de mémoire en plus.

Dans l'ensemble, ce n'est pas grave et ne devrait pas avoir d'importance dans les applications du monde réel, où la plupart du temps est consommé par la base de données et le réseau.

Bottom line: Si Scala fait vous et votre équipe (et les gens qui prennent le projet lorsque vous laisser) plus productif, alors vous devriez aller pour elle.

 29
Author: Peter Knego, 2016-06-01 18:16:50

D'autres ont répondu à cette question en ce qui concerne les boucles serrées bien qu'il semble y avoir une différence de performance évidente entre les exemples de Rex Kerr que j'ai commentés.

Cette réponse est vraiment destinée aux personnes qui pourraient enquêter sur un besoin d'optimisation en boucle serrée en tant que défaut de conception.

, je suis relativement nouveau à la Scala (environ un an), mais le sens, jusqu'à présent, c'est qu'il vous permet de reporter de nombreux aspects de la conception, de la mise en œuvre et exécution relativement facile (avec suffisamment de lecture et d'expérimentation en arrière-plan :)

Caractéristiques de conception différées:

Fonctionnalités d'implémentation différée:

Fonctionnalités d'exécution différée: (désolé, pas de liens)

  • Valeurs paresseuses Thread-safe
  • Nom de passe
  • Trucs monadiques

Ces caractéristiques, pour moi, sont celles qui nous aident à marcher sur la voie vers des applications rapides et serrées.


Les exemples de Rex Kerr diffèrent quant aux aspects de l'exécution différés. Dans l'exemple Java, l'allocation de mémoire est différée jusqu'à ce que sa taille soit calculée où la Scala exemple reporte la recherche de mappage. Pour moi, ils semblent être des algorithmes complètement différents.

Voici ce que je pense être plus un équivalent pommes à pommes pour son exemple Java:

val bigEnough = array.collect({
    case k: String if k.length > 2 && mapping.contains(k) => mapping(k)
})

Pas de collections intermédiaires, pas de Option instances, etc. Cela préserve également le type de collection, donc le type de bigEnough est Array[File] - Array's collect l'implémentation fera probablement quelque chose dans le sens de ce que fait le code Java de M. Kerr.

Les caractéristiques de conception différées que j'ai énumérées ci-dessus permettrait également aux développeurs d'API de collection de Scala d'implémenter cette implémentation de collecte rapide spécifique à un tableau dans les futures versions sans casser l'API. C'est ce à quoi je fais référence avec fouler le chemin de la vitesse.

Aussi:

val bigEnough = array.withFilter(_.length > 2).flatMap(mapping.get)

La méthode withFilter que j'ai utilisée ici au lieu de filter corrige le problème de collection intermédiaire mais il y a toujours le problème d'instance d'option.


Un exemple de vitesse d'exécution simple dans Scala est avec journalisation.

En Java, nous pourrions écrire quelque chose comme:

if (logger.isDebugEnabled())
    logger.debug("trace");

Dans Scala, c'est juste:

logger.debug("trace")

Parce que le paramètre de message à déboguer dans Scala a le type "=> String" que je considère comme une fonction sans paramètre qui s'exécute lorsqu'elle est évaluée, mais que la documentation appelle pass-by-name.

MODIFIER { Les fonctions dans Scala sont des objets, il y a donc un objet supplémentaire ici. Pour mon travail, le poids d'un banal objet vaut retrait de la possibilité d'un journal le message est inutilement évalué. }

Cela ne rend pas le code plus rapide, mais cela le rend plus susceptible d'être plus rapide et nous sommes moins susceptibles d'avoir l'expérience de parcourir et de nettoyer le code des autres en masse.

Pour moi, c'est un thème cohérent au sein de Scala.


Le code dur ne parvient pas à saisir pourquoi Scala est plus rapide, bien qu'il fasse un peu allusion.

Je pense que c'est une combinaison de réutilisation de code et du plafond de qualité de code dans Scala.

En Java, le code génial est souvent forcé de devenir un désordre incompréhensible et n'est donc pas vraiment viable dans les API de qualité de production car la plupart des programmeurs ne pourraient pas l'utiliser.

J'ai de grands espoirs que Scala puisse permettre aux einstein parmi nous d'implémenter des API beaucoup plus compétentes, potentiellement exprimées via DSL. Les API de base de Scala sont déjà loin dans cette voie.

 19
Author: Seth, 2012-05-15 05:59:48

Java et Scala compilent tous deux en bytecode JVM, donc la différence n'est pas si grande. La meilleure comparaison que vous pouvez obtenir est probablement sur le computer language benchmarks game, qui dit essentiellement que Java et Scala ont tous deux la même utilisation de la mémoire. Scala n'est que légèrement plus lent que Java sur certains des benchmarks répertoriés, mais cela pourrait simplement être dû au fait que l'implémentation des programmes est différente.

Vraiment, ils sont tous les deux si proches que ça ne vaut pas la peine s'inquiéter. L'augmentation de la productivité que vous obtenez en utilisant un langage plus expressif comme Scala vaut tellement plus que la performance minimale (le cas échéant).

 11
Author: ryeguy, 2016-06-01 18:54:17

@présentation desur le sujet - Considérations de performance Scala qui fait quelques comparaisons Java/Scala.

Outils:

Grand article de blog:

 10
Author: oluies, 2014-05-07 20:19:10

L'exemple Java n'est vraiment pas un idiome pour les programmes d'application. Un tel code optimisé peut être trouvé dans une méthode de bibliothèque système. Mais ensuite, il utiliserait un tableau du bon type, c'est-à-dire File[] et ne lancerait pas d'exception IndexOutOfBoundsException. (Différentes conditions de filtre pour compter et ajouter). Ma version serait (toujours (!) avec des accolades parce que je n'aime pas passer une heure à chercher un bug qui a été introduit en enregistrant les 2 secondes pour frapper une seule touche Eclipse):

List<File> bigEnough = new ArrayList<File>();
for(String s : array) {
  if(s.length() > 2) {
    File file = mapping.get(s);
    if (file != null) {
      bigEnough.add(file);
    }
  }
}

Mais je pourrais vous apporter beaucoup d'autres exemples de code Java laids de mon projet actuel. J'ai essayé d'éviter le style de codage commun copy&modify en prenant en compte les structures et les comportements communs.

Dans ma classe de base abstraite DAO, j'ai une classe intérieure abstraite pour le mécanisme de mise en cache commun. Pour chaque type d'objet modèle concret, il existe une sous-classe de la classe de base DAO abstraite, dans laquelle la classe interne est sous-classée pour fournir une implémentation pour la méthode qui crée l'objet métier lorsqu'il est chargé à partir de la base de données. (Nous ne pouvons pas utiliser un outil ORM car nous accédons à un autre système via une API propriétaire.)

Ce code de sous-classement et d'instanciation n'est pas du tout clair en Java et serait très lisible en Scala.

 4
Author: MickH, 2012-10-28 21:36:49