非常に短期間の大量のタスクに適したExecutorServiceはありますか?同期待機に切り替える前に、内部でビジー待機を試みるものを想定しています。タスクの順序を維持することは重要ではありませんが、メモリの一貫性を強制することは可能であるはずです(すべてのタスクが発生します-メインスレッドが制御を取り戻す前に)。
以下に投稿されたテストは、それぞれが連続して100秒を生成する100,000のタスクで構成されていますdouble
。コマンドラインパラメータとしてスレッドプールのサイズを受け入れ、常にシリアルバージョンとパラレルバージョンをテストします。(コマンドライン引数が指定されていない場合は、シリアルバージョンのみがテストされます。)パラレルバージョンは固定サイズのスレッドプールを使用し、タスクの割り当ては時間測定の一部でもありません。それでも、パラレルバージョンはシリアルバージョンよりも速くなることはありません。私は最大80スレッドを試しました(40個のハイパースレッドコアを備えたマシンで)。なんで?
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorPerfTest {
public static final int TASKS = 100000;
public static final int SUBTASKS = 100;
static final ThreadLocal<Random> R = new ThreadLocal<Random>() {
@Override
protected synchronized Random initialValue() {
return new Random();
}
};
public class SeqTest implements Runnable {
@Override
public void run() {
Random r = R.get();
for (int i = 0; i < TASKS; i++)
for (int j = 0; j < SUBTASKS; j++)
r.nextDouble();
}
}
public class ExecutorTest implements Runnable {
private final class RandomGenerating implements Callable<Double> {
@Override
public Double call() {
double d = 0;
Random r = R.get();
for (int j = 0; j < SUBTASKS; j++)
d = r.nextDouble();
return d;
}
}
private final ExecutorService threadPool;
private ArrayList<Callable<Double>> tasks = new ArrayList<Callable<Double>>(TASKS);
public ExecutorTest(int nThreads) {
threadPool = Executors.newFixedThreadPool(nThreads);
for (int i = 0; i < TASKS; i++)
tasks.add(new RandomGenerating());
}
public void run() {
try {
threadPool.invokeAll(tasks);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
public static void main(String[] args) {
ExecutorPerfTest executorPerfTest = new ExecutorPerfTest();
if (args.length > 0)
executorPerfTest.start(new String[]{});
executorPerfTest.start(args);
}
private void start(String[] args) {
final Runnable r;
if (args.length == 0) {
r = new SeqTest();
}
else {
final int nThreads = Integer.parseInt(args[0]);
r = new ExecutorTest(nThreads);
}
System.out.printf("Starting\n");
long t = System.nanoTime();
r.run();
long dt = System.nanoTime() - t;
System.out.printf("Time: %.6fms\n", 1e-6 * dt);
}
}