39 votes

Pourquoi cette solution GoLang est-elle plus rapide que la solution Java équivalente ?

Récemment, au travail, nous nous sommes amusés à répondre à la question suivante posée par IBM. https://www.research.ibm.com/haifa/ponderthis/challenges/May2015.html

Après quelques efforts, un collègue et moi sommes parvenus à deux solutions, l'une en GoLang. https://gist.github.com/walesey/e2427c28a859c4f7bc920c9af2858492#file-main-go-L57 et l'autre en Java https://gist.github.com/boyter/42df7f203c0932e37980f7974c017ec5#file-puzzle-java-L63 la méthode critique pour les performances étant playGames en Java et game en GoLang (tous deux liés ci-dessus).

Le programme Go est presque une copie littérale du programme Java, et pourtant son temps d'exécution est de ~6 secondes alors que celui de Java est d'environ ~26 secondes (sur ma machine locale). Des chiffres similaires ont été reproduits sur d'autres machines, le programme Go étant environ 5 fois plus rapide.

Le programme Go est compilé à l'aide de la version 1.7.5 et Java à l'aide de la version 1.8.0_65, tous deux fonctionnant sous macOS Sierra 10.12.3 sur un Macbook Pro retina de fin 2013 avec un processeur i5 à 2,6 GHz.

Comment se fait-il que le programme Go soit 5 fois plus rapide que le programme Java alors que la plupart des benchmarks indiquent que Java devrait avoir le même temps d'exécution ? Il s'agit simplement de mathématiques de base dans une boucle, il semble donc qu'ils devraient s'exécuter à peu près au même moment. Je pourrais comprendre qu'il faille une seconde ou plus pour le démarrage de la JVM, mais là, ça ne va pas.

Les deux programmes utilisent à peu près la même boucle. Toutes les permutations possibles des résultats du jeu sont créées et itérées pour chaque montant de départ. Il semble simplement que pour n'importe quel nombre d'opérations de bouclage dans la boucle principale, Go rivalise avec Java.

Je comprends qu'il s'agit d'un "micro" benchmark, mais je me demande pourquoi exactement le code Go est massivement plus performant que le code Java. Est-ce simplement parce que Go est plus efficace et donc plus rapide pour les boucles simples et les mathématiques ? Est-il capable de dérouler la boucle peut-être (bien que cela semble peu susceptible de produire une différence aussi massive) ?

Sinon, comment structurer un programme Java pour tirer le meilleur parti d'une simple boucle et d'une opération mathématique ?

EDITAR - Grâce à Dolda2000 j'ai modifié la version Java. Elle est maintenant à peu près aussi rapide que la version GoLang. En effet, le problème était que les parties étaient créées, ce qui obligeait la version Java à simuler plus de parties pour déterminer si la partie était suffisamment longue. Avec les modifications apportées, le programme tourne maintenant en ~6 secondes et m'a redonné confiance en Java.

Mise à jour - Voici un essai élargi qui examine plus en détail le contexte de cette question.

47voto

Dolda2000 Points 7523

Il s'avère que vos programmes ne sont pas aussi égaux que vous le pensez. Je les ai instrumentés pour voir combien de parties (c'est-à-dire de tours d'enchères individuels) ils ont simulé, et alors que la version Go a simulé 1 612 629 805 parties, la version Java a simulé 12 323 903 502 parties, soit presque un ordre de grandeur de plus.

Sur ma machine, en désactivant le multithreading pour des résultats plus prévisibles, le programme Java a duré environ 75 secondes, et le programme Go 12,5 secondes. En comparant ces résultats avec le temps d'exécution total, il apparaît que le programme Java est en fait légèrement plus rapide que le programme Go. plus rapide par partie simulée, à environ 6,1 ns, contre 7,8 ns pour le programme Go.

Je ne suis pas encore sûr de la raison pour laquelle ils simulent des nombres de jeux si différents, cependant. Peut-être que la façon dont la version Go génère les parties permet simplement de trouver beaucoup plus de terminaisons rapides.

EDITAR : En fait, cette dernière hypothèse a beaucoup de sens. La version Go commence par moduler les tours initiaux d'un jeu, alors que la version Java commence par moduler les derniers tours d'un jeu (en d'autres termes, en considérant la liste des tours comme une liste de nombres croissants à 11 chiffres en base 3, la version Go est little-endian, alors que la version Java est big-endian, pour ainsi dire), donc la version Java devra simuler beaucoup plus de débuts identiques pour arriver aux variations qui se terminent. Je n'ai pas essayé de vérifier cette hypothèse, mais j'en suis suffisamment sûr pour ne pas en ressentir le besoin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X