Dans ce code, lorsque je crée un objet dans la main
méthode, puis que j'appelle cette méthode d'objets: ff.twentyDivCount(i)
(s'exécute en 16010 ms), elle s'exécute beaucoup plus rapidement que de l'appeler en utilisant cette annotation: twentyDivCount(i)
(s'exécute en 59516 ms). Bien sûr, quand je l'exécute sans créer d'objet, je rends la méthode statique, donc elle peut être appelée dans le main.
public class ProblemFive {
// Counts the number of numbers that the entry is evenly divisible by, as max is 20
int twentyDivCount(int a) { // Change to static int.... when using it directly
int count = 0;
for (int i = 1; i<21; i++) {
if (a % i == 0) {
count++;
}
}
return count;
}
public static void main(String[] args) {
long startT = System.currentTimeMillis();;
int start = 500000000;
int result = start;
ProblemFive ff = new ProblemFive();
for (int i = start; i > 0; i--) {
int temp = ff.twentyDivCount(i); // Faster way
// twentyDivCount(i) - slower
if (temp == 20) {
result = i;
System.out.println(result);
}
}
System.out.println(result);
long end = System.currentTimeMillis();;
System.out.println((end - startT) + " ms");
}
}
EDIT: Jusqu'à présent, il semble que différentes machines produisent des résultats différents, mais en utilisant JRE 1.8. * Est l'endroit où le résultat original semble être reproduit de manière cohérente.
+PrintCompilation +PrintInlining
montreRéponses:
En utilisant JRE 1.8.0_45, j'obtiens des résultats similaires.
Enquête:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining
options VM montre que les deux méthodes sont compilées et intégréesmain
est très différent, la méthode d'instance étant optimisée de manière plus agressive, en particulier en termes de déroulement de boucle.J'ai ensuite exécuté à nouveau votre test mais avec des paramètres de déroulement de boucle différents pour confirmer la suspicion ci-dessus. J'ai exécuté votre code avec:
-XX:LoopUnrollLimit=0
et les deux méthodes s'exécutent lentement (similaire à la méthode statique avec les options par défaut).-XX:LoopUnrollLimit=100
et les deux méthodes s'exécutent rapidement (similaire à la méthode d'instance avec les options par défaut).En conclusion, il semble qu'avec les paramètres par défaut, le JIT du hotspot 1.8.0_45 ne soit pas capable de dérouler la boucle lorsque la méthode est statique (bien que je ne sache pas pourquoi il se comporte de cette façon). D'autres JVM peuvent donner des résultats différents.
la source
Juste une supposition non prouvée basée sur la réponse d'une assylie.
La JVM utilise un seuil pour le déroulement de la boucle, qui est quelque chose comme 70. Pour une raison quelconque, l'appel statique est légèrement plus grand et ne se déroule pas.
Mettre à jour les résultats
LoopUnrollLimit
dans les 52 ci-dessous, les deux versions sont lentes.C'est étrange car je suppose que l'appel statique est juste légèrement plus grand dans la représentation interne et que l'OP a rencontré un cas étrange. Mais la différence semble être d'environ 20, ce qui n'a aucun sens.
-XX:LoopUnrollLimit=51 5400 ms NON_STATIC 5310 ms STATIC -XX:LoopUnrollLimit=52 1456 ms NON_STATIC 5305 ms STATIC -XX:LoopUnrollLimit=71 1459 ms NON_STATIC 5309 ms STATIC -XX:LoopUnrollLimit=72 1457 ms NON_STATIC 1488 ms STATIC
Pour ceux qui souhaitent expérimenter, ma version peut être utile.
la source
NON_STATIC
etSTATIC
, mais ma conclusion était juste. Corrigé maintenant, merci.Quand ceci est exécuté en mode débogage, les nombres sont les mêmes pour l'instance et les cas statiques. Cela signifie en outre que le JIT hésite à compiler le code en code natif dans le cas statique de la même manière que dans le cas de la méthode d'instance.
Pourquoi le fait-il? C'est dur à dire; il ferait probablement la bonne chose s'il s'agissait d'une application plus grande ...
la source
J'ai juste modifié légèrement le test et j'ai obtenu les résultats suivants:
Production:
Dynamic Test: 465585120 232792560 232792560 51350 ms Static Test: 465585120 232792560 232792560 52062 ms
REMARQUE
Pendant que je les testais séparément, j'ai eu ~ 52 sec pour dynamique et ~ 200 sec pour statique.
Voici le programme:
public class ProblemFive { // Counts the number of numbers that the entry is evenly divisible by, as max is 20 int twentyDivCount(int a) { // Change to static int.... when using it directly int count = 0; for (int i = 1; i<21; i++) { if (a % i == 0) { count++; } } return count; } static int twentyDivCount2(int a) { int count = 0; for (int i = 1; i<21; i++) { if (a % i == 0) { count++; } } return count; } public static void main(String[] args) { System.out.println("Dynamic Test: " ); dynamicTest(); System.out.println("Static Test: " ); staticTest(); } private static void staticTest() { long startT = System.currentTimeMillis();; int start = 500000000; int result = start; for (int i = start; i > 0; i--) { int temp = twentyDivCount2(i); if (temp == 20) { result = i; System.out.println(result); } } System.out.println(result); long end = System.currentTimeMillis();; System.out.println((end - startT) + " ms"); } private static void dynamicTest() { long startT = System.currentTimeMillis();; int start = 500000000; int result = start; ProblemFive ff = new ProblemFive(); for (int i = start; i > 0; i--) { int temp = ff.twentyDivCount(i); // Faster way if (temp == 20) { result = i; System.out.println(result); } } System.out.println(result); long end = System.currentTimeMillis();; System.out.println((end - startT) + " ms"); } }
J'ai également changé l'ordre du test en:
public static void main(String[] args) { System.out.println("Static Test: " ); staticTest(); System.out.println("Dynamic Test: " ); dynamicTest(); }
Et j'ai ceci:
Static Test: 465585120 232792560 232792560 188945 ms Dynamic Test: 465585120 232792560 232792560 50106 ms
Comme vous le voyez, si dynamic est appelé avant static, la vitesse de statique a considérablement diminué.
Sur la base de ce benchmark:
REGLE DE POUCE:
Java: quand utiliser des méthodes statiques
la source
S'il vous plaît essayez:
public class ProblemFive { public static ProblemFive PROBLEM_FIVE = new ProblemFive(); public static void main(String[] args) { long startT = System.currentTimeMillis(); int start = 500000000; int result = start; for (int i = start; i > 0; i--) { int temp = PROBLEM_FIVE.twentyDivCount(i); // faster way // twentyDivCount(i) - slower if (temp == 20) { result = i; System.out.println(result); System.out.println((System.currentTimeMillis() - startT) + " ms"); } } System.out.println(result); long end = System.currentTimeMillis(); System.out.println((end - startT) + " ms"); } int twentyDivCount(int a) { // change to static int.... when using it directly int count = 0; for (int i = 1; i < 21; i++) { if (a % i == 0) { count++; } } return count; } }
la source