2011-10-18 18 views
1

私はそこに他の質問があることを知っていますが、私は初心者であり、ほとんどのコードと質問はかなり複雑でした。なぜ私はそれをできるだけシンプルに保つのですか?私はRの背景から来たが、最近私はJavaスレッドについて学びたいと思った。トピックに関するいくつかのチュートリアルを実行し、そのほとんどは以下に投稿したコードになっています。コードがあまり進んでいないことに注意してください。スレッドが数秒間実行されるので、非常に非効率です。 気づくべき主な点は、私のマシンでスレッドが実行されていないスレッドよりもはるかに速く実行されていることです。実行方法のforループの値が低いと、時には遅くなることがあります。私のハードなハードウェア(2つのコアのみ)が原因である可能性があります。また、より多くのコアを使用すると、スレッドが非並列バージョンより速く進むことがわかります。知りません。しかし、私が最も困惑しているのは、プログラムが両方の実行(並列と非並列)で実行されているときにシステムモニタを見ると、両方のコアが使用されますが、並列バージョンではほぼ100% 50〜60%。両方が同時に終了することを考慮すると、パラレルバージョンは、同じ仕事をより高速に実行するためにより多くのコンピュータパワーを使用するため、はるかに非効率的です。 一言で言えば分かります。私は間違って何をしていますか?私は、Javaチュートリアルとあまり変わらないプログラムを書いたと思った。私は以下のリンクを掲載しました。私はLinuxのubuntuをJavaのsun版で走らせる。事前にスレッドはスレッドのバージョンよりはるかに高速ではありません

http://www.java2s.com/Tutorial/Java/0160__Thread/0020__Create-Thread.htm

import java.util.ArrayList; 

public class Main { 
    public static void main(String[] args) { 
     ArrayList<PermutateWord> words = new ArrayList<PermutateWord>(); 
     System.out.println(Runtime.getRuntime().availableProcessors()); 
     for(int i = 0; i < Runtime.getRuntime().availableProcessors();i++){ 
      words.add(new PermutateWord("Christoph")); 
     } 
     System.out.println("Run as thread"); 
     long d = System.currentTimeMillis(); 
     for (PermutateWord w : words) { 
      w.start(); 
     } 
     for (PermutateWord w : words) { 
      try { 
       w.join(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     for (PermutateWord w : words) { 
      System.out.println(w.getWord()); 
     } 
     System.out.println(((double)(System.currentTimeMillis()-d))/1000+"\n"); 
     System.out.println("No thread"); 
     d = System.currentTimeMillis(); 
     for (PermutateWord w : words) { 
      w.run(); 
     } 
     for (PermutateWord w : words) { 
      System.out.println(w.getWord()); 
     } 
     System.out.println(((double)(System.currentTimeMillis()-d))/1000+"\n"); 
    } 
} 
class PermutateWord extends Thread {  
    private String word; 
    public PermutateWord (String word){ 
     this.word = word; 
    } 
    public void run() { 
     java.util.Random rand = new java.util.Random(); 
     for(int i = 0; i <8000000;i++){ 
      word = swap(word,rand.nextInt(word.length()), rand.nextInt(word.length())); 
     } 
    } 
    private String swap(String word2, int r1, int r2) { 
     char[] wordArray = word2.toCharArray(); 
     char c = wordArray[r1]; 
     wordArray[r1] = wordArray[r2]; 
     wordArray[r2] = c; 
     return new String(wordArray); 
    } 
    public String getWord(){ 
     return word; 
    } 
} 

おかげ

クリストフ

+0

@akappaのように、あなたは別のスレッドで何かしていると言いました。あなたのアプリケーションの複数のインスタンスを同時に実行しているということです。彼らはタスクを共有していませんが、それぞれがsametaskをやっています.java2sには、それに留意しても良い例がありません。 – Shahzeb

+0

私のデュアルコアWindowsマシンでは、複数のスレッドで11.966秒、シングルスレッドで平均18.3秒*を5回実行します。 – Bhaskar

+0

@Shahzeb akappaの答えに対する私のコメントを参照してください。この並列化のアプローチは必ずしも有用ではありませんが、パフォーマンスが向上するはずです。 –

答えて

5

時間の大半は、同期されなければならない、一時的な文字列を割り当て、dealocating過ごすです。並行して行うことができる作業は簡単で、複数のスレッドではそれほど多くの利益を得られません。

Math.random()も同期させる必要があります。スレッドごとにローカルjava.util.Randomを作成する方が良い結果が得られます。

java.util.Random rand = new java.util.Random(); 

public void run() { 
    for(int i = 0; i <8000000;i++){ 
     word = swap(word,rand.nextInt(word.length()), rand.nextInt(word.length())); 
    } 
} 

しかし、あなたは本当にswap機能を最適化することに焦点を当てるべきです。私はそれがあなたの望むことをするかどうかはわかりませんが、それは非常に非効率的だと確信しています。 +Stringで高価です。 +ごとに、JVMは新しいStringを割り当てる必要があります。これは遅く、複数のスレッドでうまく動作しません。 2文字をスワップするだけの場合は、Stringの代わりにchar[]を使用することを検討してください。それははるかに簡単ではるかに速くなければなりません。

編集:

private String swap(String word2, int r1, int r2) { 
    char[] wordArray = word2.toCharArray(); 
    char c = wordArray[r1]; 
    wordArray[r1] = wordArray[r2]; 
    wordArray[r2] = c; 
    return new String(wordArray); 
} 

これは、はるかに優れています。しかし、あなたはまだ2つの割り当てをしています。 toCharArray()およびnew Stringは両方ともメモリを割り当てます。残りのプログラムは非常にシンプルなので、2つの割り当ては実行時間の90%を占めます。

+0

これはJavaの専門家にとってはおそらく非常に馬鹿だと思いますが、どうすればいいでしょうか? – Christoph

+0

ありがとう!どちらの提案もパフォーマンスを大幅に改善しましたが、マルチスレッドには何の影響もありませんでした。あなたの答えで言ったように。並列に行うことができる作業が簡単で、複数のスレッドが私に大きな利益をもたらさない理由を私に説明できますか?すべての記事を読んで、それがどのように機能するかについての私の理解がどこかに戻ってきたようだ。 – Christoph

+0

これは私のために非常にうまくいった。 'PermutateWord'の中にはローカルなランダム' private random = new Random(); '' Math.random() 'の代わりに' random.nextFloat() 'を使うべきです – Gray

0

私はJoinループにThread.sleep(1000)を入れることから多くのマイナスを得ました。 経験によると、java.util.Random.nextFloat()は10%しか買っていませんでした。

でも、8コアマシンでは16秒で両方の部分が実行され、上記の同期化により がシリアル化されていることがわかります。しかし、良い、悲しみ、 せずにそれは10倍遅く実行されていた。

関連する問題