2014-09-15 4 views
3

Je suis un cours d'analyse d'algorithmes et d'algorithmes. Et je veux savoir combien une simple opération +, -, /, * peut prendre sur mon ordinateur. Alors j'écris une montre simple d'arrêt comme suit:Combien de temps dure une opération simple en Java en nano secondes?

public class NanosecondsStopWatch implements StopWatch { 

    private PrintStream stream; 

    public NanosecondsStopWatch(PrintStream stream) { 
     this.stream = stream; 
    } 

    @Override 
    public void timeAndPrint(Action action) { 

     long start = System.nanoTime(); 

     action.doAction(); 

     long end = System.nanoTime(); 

     stream.println(end-start); 
    } 

} 


public class TestingOperationsTime { 

    public static void main(String[] strings) { 

     StopWatch watch = new NanosecondsStopWatch(System.out); 

     watch.timeAndPrint(new Action() { 
      @Override 
      public void doAction() { 
       int i= 2*2; 
      } 
     }); 

     watch.timeAndPrint(new Action() { 
      @Override 
      public void doAction() { 
       int i= 2/2; 
      } 
     }); 

     watch.timeAndPrint(new Action() { 
      @Override 
      public void doAction() { 
       int i= 2-2; 
      } 
     }); 

     watch.timeAndPrint(new Action() { 
      @Override 
      public void doAction() { 
       int i= 2+2; 
      } 
     }); 

    } 
} 

Les résultats sont comme suit

2529 
454 
355 
335 

Cependant, si je change l'ordre des opérations dire comme ceci:

public class TestingOperationsTime { 

    public static void main(String[] strings) { 

     StopWatch watch = new NanosecondsStopWatch(System.out); 

     watch.timeAndPrint(new Action() { 
      @Override 
      public void doAction() { 
       int i= 2-2; 
      } 
     }); 

     watch.timeAndPrint(new Action() { 
      @Override 
      public void doAction() { 
       int i= 2*2; 
      } 
     }); 

     watch.timeAndPrint(new Action() { 
      @Override 
      public void doAction() { 
       int i= 2/2; 
      } 
     }); 

     watch.timeAndPrint(new Action() { 
      @Override 
      public void doAction() { 
       int i= 2+2; 
      } 
     }); 

    } 
} 

Le le résultat est toujours le même presque:

2494 
332 
309 
326 

Comment pouvez-vous expliquer ce comportement?

  • OS: Ubuntu 14.04
  • Java: 1.7.0_65
  • OpenJDK Runtime Environment (IcedTea 2.5.1) (~ 7u65-2.5.1-4ubuntu1 0.14.04.2)
  • OpenJDK 64 bits VM Server (build-B04 24,65, mode mixte)
  • javac 1.7.0_67
+9

Parce qu'ils sont expressions_ _constant, '2 * 2',' 2/2', '2-2' et' 2 + 2' sont évalués au moment de la compilation . Vos horaires ne reflètent pas les temps de calcul. – rgettman

+0

duplication possible de [Y at-il un chronomètre en Java] (http://stackoverflow.com/questions/8255738/is-there-a-stopwatch-in-java) – StackFlowed

+3

Si vous voulez savoir combien de temps quelque chose prend, effectuez le action plusieurs fois, puis calculer une moyenne. – Malt

Répondre

2

Il y aura toujours des différences, parce qu'il ya d'autres processus en cours d'exécution sur votre ordinateur et selon un processus OS Les autres auront la priorité sur les autres. Vous ne pouvez pas vraiment prédire exactement combien de millisecondes une seule opération peut prendre. Cela dépend également de la rapidité de l'unité centrale de votre ordinateur.

5

De nombreux facteurs influencent la quantité de temps système utilisée par votre code. Par exemple, si l'ordinateur exécute un code context switch alors que votre code est en cours d'exécution, le temps que vous passez inclut le temps passé à exécuter un autre programme.

Pour atténuer cela, vous pouvez lancer la minuterie plusieurs fois, par exemple des milliers ou des millions, et prendre une moyenne.

De plus, comme le souligne @rgettman, le compilateur optimisera probablement ces calculs car ils sont effectués sur des valeurs constantes. Cela signifie que vous ne synchronisez que le temps d'appel d'une méthode et l'impression de sortie et non le temps d'effectuer le calcul.

2

Le compilateur évalue les expressions Constantes à la compilation, vous devriez en faire une méthode qui reçoit les paramètres. Deuxièmement, l'appel système à la montre prend plus de quelques nano secondes, donc cette vérification ne sera jamais forcée, ce que vous obtenez réellement, c'est combien de temps il faut à Java pour avoir le temps.

1

Ce n'est pas une chose simple. En bref, Java n'est pas la bonne langue pour mesurer les choses.

Java est un langage compilé juste à temps. Cela signifie que le code que vous écrivez s'exécute dans une «machine virtuelle» et qu'il peut être entièrement interprété, entièrement compilé ou partiellement compilé. C'est pourquoi, en général, le premier passage est toujours plus lent: il est toujours interprété. Ce n'est que plus tard que la machine virtuelle peut décider de la compiler et d'échanger le code compilé avec la procédure interprétée.

De plus, il y a un surcoût important dans les procédures du système d'appel de la JVM, qui modifie en quelque sorte vos mesures. Alors oui, vous pouvez faire des mesures, si vous faites d'abord une boucle de «réchauffement», pour faire comprendre à la VM qu'une méthode donnée doit être compilée, et ensuite ignorer le premier résultat. Mais les résultats ne mesurent pas exactement les performances de votre CPU. Vous devriez utiliser C ou l'assembleur pour cela, et même dans ce cas, vous devez gérer les changements de contexte et la gestion du système d'exploitation, qui modifient vos résultats. PS: Et oui, je ne l'ai pas mentionné, car il y avait déjà 4 autres réponses à ce sujet, mais le compilateur Java n'est pas si stupide, et il évaluera le fonctionnement constant au moment de la compilation. i=2*2 est compilé à i=4, donc vous ne mesurez pas le temps de multiplication, mais seulement le temps d'affectation.

+4

"Java n'est pas le bon langage pour mesurer les choses." Si vous voulez savoir combien de temps les choses prennent en Java, la langue *** *** seulement pour les mesurer est Java. Cependant, les microbenchmarks sont difficiles à corriger, et encore plus difficiles sur un runtime avec un compilateur Just-in-Time. –

0

2 principaux problèmes (1) vous appelez une fonction, qui consomme beaucoup de ressources. (2) vous l'exécutez une seule fois. Si vous exécutez l'instruction directement, ou si vous l'exécutez plusieurs fois, vous verrez que le temps d'exécution est très faible. Ci-dessous le résultat est time=0ns

public class PerfTest { 
public static void main(String[] args) { 
    long t1 = System.nanoTime(); 
    int i = 2 * 2; 
    long t2 = System.nanoTime(); 
    System.out.printf("time=%dns", t2 -t1); 
} 

}

Questions connexes