2009-09-18 12 views
2

fichier: Example1.javaPourquoi deux threads Java (dans certains cas) sont-ils deux fois plus rapides qu'un?

public class Example1 implements Runnable { 

    public void run() { 
     for(int i = 0; i < 100000000; i++) { 
      int x = 5; 
      x = x * 4; 
      x = x % 3; 
      x = x + 9000; 
      x = x * 923; 
     } 
    } 

    public static void task() { 
     for(int i = 0; i < 100000000; i++) { 
      int x = 5; 
      x = x * 4; 
      x = x % 3; 
      x = x + 9000; 
      x = x * 923; 
     } 
     for(int i = 0; i < 100000000; i++) { 
      int x = 9; 
      x = x * 2; 
      x = x % 4; 
      x = x + 3241; 
      x = x * 472; 
     } 
    } 

    public static void main(String[] args) { 

     long startTime = System.currentTimeMillis(); 
      Example1.task(); 
      Example1.task(); 
      Example1.task(); 
      Example1.task(); 
      Example1.task(); 
     long stopTime = System.currentTimeMillis(); 
     long runTime = stopTime - startTime; 
     System.out.println("Run time for one thread: " + runTime); 


     startTime = System.Example1(); 
      (new Thread(new Example1())).start(); 
      (new Thread(new Example2())).start(); 
      (new Thread(new Example1())).start(); 
      (new Thread(new Example2())).start(); 
      (new Thread(new Example1())).start(); 
      (new Thread(new Example2())).start(); 
      (new Thread(new Example1())).start(); 
      (new Thread(new Example2())).start(); 
      (new Thread(new Example1())).start(); 
      (new Thread(new Example2())).start(); 
     stopTime = System.currentTimeMillis(); 
     runTime = stopTime - startTime; 
     System.out.println("Run time for two threads: " + runTime); 


    } 

} 

fichier: Example2.java

public class Example2 implements Runnable { 

    public void run() { 
     for(int i = 0; i < 100000000; i++) { 
      int x = 9; 
      x = x * 2; 
      x = x % 4; 
      x = x + 3241; 
      x = x * 472; 
     }   
    } 
} 

Quand je lance cela, il génère:

temps d'exécution pour un thread: 1219

Temps d'exécution pour deux threads: 281

ou quelque chose de très proche.

Pourquoi y a-t-il une telle différence? Pourquoi le scinder en deux threads va-t-il plus de deux fois plus vite que de le lancer directement?

+0

Je pense que vous devriez être plus explicite avec le code pour avoir une idée exacte de ce que vous faites. – yeyeyerman

+0

Vous n'êtes pas assez prudent pour prendre en compte la compilation juste-à-temps. Vous devez exécuter le code avant le début du test de performance suffisamment longtemps pour que le JIT fasse son travail. – starblue

Répondre

19

En fait, vous n'attendez pas que les threads se terminent. Une fois que vous démarrez un thread, vous devez ensuite appeler .join() pour l'attendre. Qu'est-ce qui se passe ici, c'est que tous vos fils commencent et dès que le dernier a commencé, vous l'horloge et ensuite calculer l'heure d'arrêt. Cela signifie que vos threads sont toujours en cours d'exécution en arrière-plan.

Éditer: La raison pour laquelle le premier prend si longtemps est parce que vous faites une série d'appels synchrones, alors que la création d'un thread et le démarrage génère une tâche asynchrone.

Edit 2: Voici un diagramme de séquence de serviette de ce qui se passe dans votre premier test: http://www.websequencediagrams.com/cgi-bin/cdraw?lz=TWFpbi0-RXhhbXBsZTE6IFRhc2sgc3RhcnRlZAphY3RpdmF0ZSAAGAgKACEILS0-TWFpbjogZG9uZQpkZQAYEgABWAABWAABgTFlMQo&s=napkin

Voici un diagramme de séquence de serviette de ce qui se passe dans votre deuxième test: http://www.websequencediagrams.com/cgi-bin/cdraw?lz=TWFpbi0tPkFub255bW91cyBUaHJlYWQ6IFN0YXJ0IEV4YW1wbGUxLnRhc2soKQoACSYyAAEuAAFdAAGBOwCCPjoAgyIGPk1haW46ICJIb3cgbG9uZyBkaWQgdGhhdCB0YWtlPyIKAINmEC0AKwhUYXNrcyBiZWdpbiB0byBmaW5pc2guLi4gKHNvbWUgbWF5IGhhdmUgZW5kZWQgZWFybGllcikK&s=napkin

Edit 3: Je réalisé que le deuxième diagramme de séquence pointe toutes les flèches vers le/même/thread. Ce sont en fait des threads différents, chaque appel.

+2

+1: WebSequenceDiagrams.com == génial. – Juliet

+0

+1 pour les diagrammes de séquence Web :-) –

2

L'appel start() sur un thread retourne immédiatement car il met en file d'attente le thread. Le fil lui-même commencera à tourner en arrière-plan un peu plus tard.

1

Voici ce que je reçois avec votre code d'ajouter se joindre aux discussions:

temps d'exécution pour un fil: 566

temps d'exécution pour deux fils: 294

Alors précédent les réponses sont correctes.

EDIT: J'ai ajouté des jointures de cette façon. Vous pouvez le faire mieux, mais ce n'est pas grave:

Thread[] t = new Thread[10]; 
    (t[0] = new Thread(new Example1())).start(); 
    (t[1] = new Thread(new Example2())).start(); 
    (t[2] = new Thread(new Example1())).start(); 
    (t[3] = new Thread(new Example2())).start(); 
    (t[4] = new Thread(new Example1())).start(); 
    (t[5] = new Thread(new Example2())).start(); 
    (t[6] = new Thread(new Example1())).start(); 
    (t[7] = new Thread(new Example2())).start(); 
    (t[8] = new Thread(new Example1())).start(); 
    (t[9] = new Thread(new Example2())).start(); 

    for (Thread t1: t) { 
     try { 
      t1.join(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 

Vous devez rejoindre chaque thread. Cependant, vous ne perdez pas votre temps à attendre dans join() car les autres threads ne sont pas bloqués. Si le thread a fini, c'est l'exécution avant que vous n'appeliez à rejoindre, vous continuez simplement au thread suivant.

En outre, que signifie votre dernier commentaire?

+0

Où ajoutez-vous rejoindre? À la fin de la liste de (nouveau Thread (new Example2())). Start(); ? – 827

+0

Aussi, ce sont plus les différences de vitesse que je m'attendais. – 827

+0

Oui, vous devez ajouter join à la fin de la liste des démarrages (comme cet exemple). Si vous l'ajoutez entre les deux, vous attendez que ce thread soit complet avant de commencer le suivant (en évitant toute forme de parallélisme). – Malaxeur