コードは次のとおりです。もちろん
int s = 32343;
ArrayList<Integer> al = new ArrayList<Integer>(s);
for (int c = 0; c < s; c++) {
al.add(c);
}
Iterator<Integer> it = al.iterator();
if (it.hasNext()) {
int c = it.next();
c = c++;
}
あなたがs
の値を増やした場合、これはあなたがリストに入れてどのように多くの事s
制御するので、パフォーマンスが低下します。しかし、これは並行性やスケーラビリティとはほとんど関係がありません。数千または数百万回の捨て去り計算を行う時間を無駄にするようにコンピュータに指示するコードを書くと、もちろんパフォーマンスは低下します。 n
がs
に等しい、より技術的に言えば
、コードのこのセクションの時間複雑性はO(2n)
である(それはリストを構築するためにn
操作を要し、その後n
操作はそれを反復し、それぞれの値をインクリメントします)。したがって、あなたがs
を大きくするほど、このコードを実行するのに時間がかかります。
これが並行性の利点を小さくするように見える理由については、s
が大きくなるにつれてメモリの影響を考慮していますか?たとえば、Javaヒープがディスクにスワップアウトされずにメモリ内のすべてを保持するのに十分な大きさであることを確認してください。何もスワップアウトされなくても、ArrayList
の長さを大きくすることで、ガベージコレクタに実行時の処理(実行頻度を上げる可能性があります)が増えます。実装によっては、ガベージコレクタが実行されるたびにすべてのスレッドを一時停止している可能性があります。
スレッドごとに単一のArrayList
インスタンスを割り当ててスレッドを作成した時点で、毎回新しいリストを作成するのではなくisPrime()
の呼び出しでそれを再利用すれば、改善されますか?
編集:ここまでの修正版です:http://pastebin.com/6vR7Uhez
は、それは私のマシン上で次のような出力が得られます。
------------------start------------------
1 threads' runtimes:
1 3766.0
maximum: 3766.0
main time: 3766.0
------------------end------------------
------------------start------------------
2 threads' runtimes:
1 897.0
2 2483.0
maximum: 2483.0
main time: 2483.0
------------------end------------------
------------------start------------------
4 threads' runtimes:
1 576.0
2 1473.0
3 568.0
4 1569.0
maximum: 1569.0
main time: 1569.0
------------------end------------------
------------------start------------------
8 threads' runtimes:
1 389.0
2 965.0
3 396.0
4 956.0
5 398.0
6 976.0
7 386.0
8 933.0
maximum: 976.0
main time: 978.0
------------------end------------------
...スレッド数を上げているとほぼリニアスケーリングを示していますアップ。私が修正した問題は、上に挙げた点とJohn Vint(今削除された)の答え、そしてConcurrentLinkedQueue
構造の間違った/不必要な使用と疑わしいタイミングロジックの組み合わせだった。
我々はGCログを有効にして、両方のバージョンをプロファイルした場合、我々は元のバージョンが変更されたバージョンよりも、ガベージコレクションの実行についての10倍ほどの時間を費やしていることがわかります。
Original: [ParNew: 17401K->750K(19136K), 0.0040010 secs] 38915K->22264K(172188K), 0.0040227 secs]
Modified: [ParNew: 17024K->0K(19136K), 0.0002879 secs] 28180K->11156K(83008K), 0.0003094 secs]
間のように私には意味定数リスト割り当てとInteger
自動ボクシングの場合、元の実装はあまりにも多くのオブジェクトを突っ込んでいたため、GCに負担がかかりすぎて、スレッドのパフォーマンスが悪くなったり、より多くのスレッドを作成します。
Javaの並行性のスケーリングがうまくいかない場合は、タスクが大小どちらであっても、どのようにメモリを使用しているのか、隠されている可能性があることに注意する必要があります落とし穴や非効率性を減らし、非効率なビットを最適化します。
はい、16コアCPUでテストしました。 –
別の8コアコンピュータで同じ設定をテストしたところ、スケーラビリティが再び現れました。私はこのおもちゃプログラムを使用して、次回のどこかでJava並行処理を試してみると、最初のステップのテストを行います。ところで、プライマー番号を計算するより良い方法は、スレッドの範囲を分割するのではなく、スレッドが候補番号を保持する並行キューを共有できるようにすることです。このおもちゃプログラムで共有データを避けたいだけです。 –