Executor フレームワークについて詳しく知るために、いくつかの Java コードを作成しました。
具体的には、コラッツ仮説を検証するコードを書きました。これは、次の関数を任意の整数に繰り返し適用すると、最終的に 1 になることを示しています。
f(n) = ((n % 2) == 0) ? n/2 : 3*n + 1
CH はまだ証明されていませんが、Executor について学ぶには良い方法だと思いました。各スレッドには、チェックする整数の範囲 [l,u] が割り当てられます。
具体的には、私のプログラムは 3 つの引数を取ります - N (CH をチェックしたい数)、RANGESIZE (スレッドが処理しなければならない間隔の長さ)、および NTHREAD、スレッドプールのサイズです。
私のコードは正常に動作しますが、1 スレッドから 4 スレッドに変更したときは 30% 程度の速度向上が期待したほどではありませんでした。
私の論理では、計算は完全に CPU バウンドであり、各サブタスク (CH の固定サイズ範囲のチェック) にはほぼ同じ時間がかかります。
3 倍から 4 倍の速度の向上が見られない理由について、誰か考えがありますか?
スレッドの数を (マシン、JVM、OS とともに) 増やしてランタイムを報告できれば、それも素晴らしいことです。
仕様
ランタイム:
java -d64 -server -cp . Collatz 10000000 1000000 4 => 4 スレッド、28412 ミリ秒かかります
java -d64 -server -cp . Collatz 10000000 1000000 1 => 1 スレッド、38286 ミリ秒かかります
プロセッサー:
2.4GHZ、4GB のクアッドコア Intel Q6600。マシンがアンロードされます。
ジャワ:
Java バージョン "1.6.0_15" Java(TM) SE ランタイム環境 (ビルド 1.6.0_15-b03) Java HotSpot(TM) 64 ビット サーバー VM (ビルド 14.1-b02、混合モード)
OS:
Linux quad0 2.6.26-2-amd64 #1 SMP Tue Mar 9 22:29:32 UTC 2010 x86_64 GNU/Linux
コード: (投稿するコードを取得できません。SO 要件には長すぎると思います。ソースはGoogle ドキュメントで入手できます。
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyRunnable implements Runnable {
public int lower;
public int upper;
MyRunnable(int lower, int upper) {
this.lower = lower;
this.upper = upper;
}
@Override
public void run() {
for (int i = lower ; i <= upper; i++ ) {
Collatz.check(i);
}
System.out.println("(" + lower + "," + upper + ")" );
}
}
public class Collatz {
public static boolean check( BigInteger X ) {
if (X.equals( BigInteger.ONE ) ) {
return true;
} else if ( X.getLowestSetBit() == 1 ) {
// odd
BigInteger Y = (new BigInteger("3")).multiply(X).add(BigInteger.ONE);
return check(Y);
} else {
BigInteger Z = X.shiftRight(1); // fast divide by 2
return check(Z);
}
}
public static boolean check( int x ) {
BigInteger X = new BigInteger( new Integer(x).toString() );
return check(X);
}
static int N = 10000000;
static int RANGESIZE = 1000000;
static int NTHREADS = 4;
static void parseArgs( String [] args ) {
if ( args.length >= 1 ) {
N = Integer.parseInt(args[0]);
}
if ( args.length >= 2 ) {
RANGESIZE = Integer.parseInt(args[1]);
}
if ( args.length >= 3 ) {
NTHREADS = Integer.parseInt(args[2]);
}
}
public static void maintest(String [] args ) {
System.out.println("check(1): " + check(1));
System.out.println("check(3): " + check(3));
System.out.println("check(8): " + check(8));
parseArgs(args);
}
public static void main(String [] args) {
long lDateTime = new Date().getTime();
parseArgs( args );
List<Thread> threads = new ArrayList<Thread>();
ExecutorService executor = Executors.newFixedThreadPool( NTHREADS );
for( int i = 0 ; i < (N/RANGESIZE); i++) {
Runnable worker = new MyRunnable( i*RANGESIZE+1, (i+1)*RANGESIZE );
executor.execute( worker );
}
executor.shutdown();
while (!executor.isTerminated() ) {
}
System.out.println("Finished all threads");
long fDateTime = new Date().getTime();
System.out.println("time in milliseconds for checking to " + N + " is " +
(fDateTime - lDateTime ) +
" (" + N/(fDateTime - lDateTime ) + " per ms)" );
}
}