2017-01-03 5 views
1

Javaマルチスレッド化されたアプリケーションに慣れようとしています。私は非常によく並列化できる単純なアプリケーションを考えようとしました。私は、ベクターの追加はそうするのに適していると思っていました。 しかし、私のLinuxサーバ(4つのコアを持っています)で走っているとき、私はスピードを上げません。 4,2,1スレッドで実行する時間はほぼ同じです。Javaマルチスレッド化されたベクトルの追加

ここに私が思い付いたコードです:

public static void main(String[]args)throws InterruptedException{ 

    final int threads = Integer.parseInt(args[0]); 
    final int length= Integer.parseInt(args[1]); 
    final int balk=(length/threads); 
    Thread[]th = new Thread[threads]; 

    final double[]result =new double[length]; 

    final double[]array1=getRandomArray(length); 
    final double[]array2=getRandomArray(length); 

    long startingTime =System.nanoTime(); 
    for(int i=0;i<threads;i++){ 
     final int current=i; 
     th[i]=new Thread(()->{ 
      for(int k=current*balk;k<(current+1)*balk;k++){ 
       result[k]=array1[k]+array2[k]; 
      } 
     }); 
     th[i].start(); 
    } 
    for(int i=0;i<threads;i++){ 
     th[i].join(); 
    } 
    System.out.println("Time needed: "+(System.nanoTime()-startingTime)); 


} 

長さは常にスレッドとgetRandomArray(の倍数である)は、0と1の

実行時間とのダブルスのランダムな配列を作成します1スレッドのために:74211325ns
実行時間4スレッドのための:89215100ns
長= 10000000 実行時間2スレッドのための84579446nsここでは

getRandomArrayのコードは()です:

private static double[]getRandomArray(int length){ 
    Random random =new Random(); 
    double[]array= new double[length]; 
    for(int i=0;i<length;i++){ 
     array[i]=random.nextDouble(); 
    } 
    return array; 
} 

私は任意の助けをいただければ幸いです。

+0

長さが「10000000」という巨大な値で試しましたか? –

+0

長さ= 10000000のテストを実行し、スピードアップを見ることができません。コードの下の私の編集を参照してください。 – CheckersGuy

+0

'getRandomArray'のコードを私に投稿できますか? –

答えて

2

次のコードでは、違いがわかります。それを試してみてください。

public static void main(String[]args)throws InterruptedException{ 

    for(int z = 0; z < 10; z++) { 

     final int threads = 1; 
     final int length= 100_000_000; 
     final int balk=(length/threads); 
     Thread[]th = new Thread[threads]; 

     final boolean[]result =new boolean[length]; 

     final boolean[]array1=getRandomArray(length); 
     final boolean[]array2=getRandomArray(length); 

     long startingTime =System.nanoTime(); 
     for(int i=0;i<threads;i++){ 
      final int current=i; 
      th[i]=new Thread(()->{ 
       for(int k=current*balk;k<(current+1)*balk;k++){ 
        result[k]=array1[k] | array2[k]; 
       } 
      }); 
      th[i].start(); 
     } 
     for(int i=0;i<threads;i++){ 
      th[i].join(); 
     } 

     System.out.println("Time needed: "+(System.nanoTime()-startingTime)*1.0/1000/1000); 

     boolean x = false; 
     for(boolean d : result) { 
      x |= d; 
     } 
     System.out.println(x); 
    } 
} 

最初にまずコードをウォームアップする必要があります。この方法で、コンパイルされたコードを測定します。最初の2回の反復は同じ(ほぼ)時間ですが、次の反復は異なります。私のマシンはあまりメモリを持っていないので、私は2倍をbooleanに変更しました。これは私に巨大な配列を割り当てることを可能にし、また、より多くのCPUを消費させる。

コメントにはリンクがあります。私はそれを読むことをお勧めします。

+0

ありがとうございます。私はテストを実行し、最終的にスピードアップを見ることができました:Pもうちょっと質問があります。私たちがコードを実行するときにJITコンパイラが最適化するという「ウォームアップ」の最初の理由がありますか? – CheckersGuy

+0

@CheckersGuy。まず、コードは通訳の助けを借りて実行されます。これは非常に遅いです。あなたのコードのいくつかの部分が数回実行された後(あなたの場合、すべての作業が終わったループです)、コンパイルされます。デフォルトでは、コンパイルにはいくつかのレベル(階層化されたコンパイル)があるため、最後のレベルが適用されるまでコードを多く呼び出す必要があります。 –

2

こんにちは私の側からあなたがあなたのコアの共有の仕組みを見てみると、あなたはすべてのコアに対して非常に単純な作業をすることができますが、それらは常に別のスレッド(基本的には、スレッドは複雑な作業をしていて、少量の時間で共有リソースを使用します)。あなたのコードを使って、私はこのようなことをしました。そのような場合は、ほぼ正確に2倍のスピードアップと4倍のスピードアップが必要です。あなたが見

public static void main(String[]args)throws InterruptedException{ 
     for(int a=0; a<5; a++) { 
      final int threads = 2; 
      final int length = 10; 
      final int balk = (length/threads); 
      Thread[] th = new Thread[threads]; 
      System.out.println(Runtime.getRuntime().availableProcessors()); 
      final double[] result = new double[length]; 

      final double[] array1 = getRandomArray(length); 
      final double[] array2 = getRandomArray(length); 

      long startingTime = System.nanoTime(); 
      for (int i = 0; i < threads; i++) { 
       final int current = i; 
       th[i] = new Thread(() -> { 
        Random random = new Random(); 
        int meaningless = 0; 
        for (int k = current * balk; k < (current + 1) * balk; k++) { 
         result[k] = array1[k] + array2[k]; 
         for (int j = 0; j < 10000000; j++) { 
          meaningless+=random.nextInt(10); 
         } 
        } 
       }); 
       th[i].start(); 
      } 
      for (int i = 0; i < threads; i++) { 
       th[i].join(); 
      } 
      System.out.println("Time needed: " + ((System.nanoTime() - startingTime) * 1.0)/1000000000 + " s"); 

     } 
    } 

あなたのコードの中で最も時間が大きなテーブルを構築し、その後、スレッドは非常に高速な実行しているによって消費される時間のほとんどを作成することによって消費されているので、自分の仕事は時間のあなたの計算が間違っていることを非常に高速でありますスレッド。このような事前計算されたループで動作するコードを呼び出すと:

long startingTime =System.nanoTime(); 
    for(int k=0; k<length; k++){ 
     result[k]=array1[k]|array2[k]; 
    } 
    System.out.println("Time needed: "+(System.nanoTime()-startingTime)); 

これは2つのスレッドでコードより2倍速く働いていました。この場合、私が何を意味しているのかを理解して、私のスレッドにもっと無意味な仕事を与えたときの私の要点を見てくれることを願っています。

関連する問題