実行できる最適なスレッド数を知りたいのですが。通常、これはに等しくなりRuntime.getRuntime().availableProcessors()
ます。
ただし、ハイパースレッディングをサポートするCPUでは、返される数は2倍になります。さて、いくつかのタスクではハイパースレッディングは良いですが、他のタスクでは何もしません。私の場合、それは何もしないのではないかと思うので、返された数Runtime.getRuntime().availableProcessors()
を2で割る必要があるかどうかを知りたいと思います。
そのためには、CPUがハイパースレッディングであるかどうかを推測する必要があります。したがって、私の質問-Javaでそれを行うにはどうすればよいですか?
ありがとう。
編集
OK、コードのベンチマークを行いました。これが私の環境です:
- Lenovo ThinkPad W510(つまり、4コアとハイパースレッディングを備えたi7 CPU)、16GのRAM
- Windows 7
- 105Mから16Mの範囲のzipサイズの84のzipCSVファイル
- すべてのファイルはメインスレッドで1つずつ読み取られます。HDへのマルチスレッドアクセスはありません。
- 各CSVファイルの行にはいくつかのデータが含まれており、そのデータは解析され、高速の文脈自由テストによって行が関連しているかどうかが判断されます。
- 関連する各行には、2つのdouble(好奇心旺盛な人のために経度と緯度を表す)が含まれています。これらは強制的に1つにされ
Long
、共有ハッシュセットに格納されます。
したがって、ワーカースレッドはHDから何も読み取りませんが、コンテンツの解凍と解析(opencsvライブラリを使用)に専念します。
以下は、退屈な詳細なしのコードです。
public void work(File dir) throws IOException, InterruptedException {
Set<Long> allCoordinates = Collections.newSetFromMap(new ConcurrentHashMap<Long, Boolean>());
int n = 6;
// NO WAITING QUEUE !
ThreadPoolExecutor exec = new ThreadPoolExecutor(n, n, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());
StopWatch sw1 = new StopWatch();
StopWatch sw2 = new StopWatch();
sw1.start();
sw2.start();
sw2.suspend();
for (WorkItem wi : m_workItems) {
for (File file : dir.listFiles(wi.fileNameFilter)) {
MyTask task;
try {
sw2.resume();
// The only reading from the HD occurs here:
task = new MyTask(file, m_coordinateCollector, allCoordinates, wi.headerClass, wi.rowClass);
sw2.suspend();
} catch (IOException exc) {
System.err.println(String.format("Failed to read %s - %s", file.getName(), exc.getMessage()));
continue;
}
boolean retry = true;
while (retry) {
int count = exec.getActiveCount();
try {
// Fails if the maximum of the worker threads was created and all are busy.
// This prevents us from loading all the files in memory and getting the OOM exception.
exec.submit(task);
retry = false;
} catch (RejectedExecutionException exc) {
// Wait for any worker thread to finish
while (exec.getActiveCount() == count) {
Thread.sleep(100);
}
}
}
}
}
exec.shutdown();
exec.awaitTermination(1, TimeUnit.HOURS);
sw1.stop();
sw2.stop();
System.out.println(String.format("Max concurrent threads = %d", n));
System.out.println(String.format("Total file count = %d", m_stats.getFileCount()));
System.out.println(String.format("Total lines = %d", m_stats.getTotalLineCount()));
System.out.println(String.format("Total good lines = %d", m_stats.getGoodLineCount()));
System.out.println(String.format("Total coordinates = %d", allCoordinates.size()));
System.out.println(String.format("Overall elapsed time = %d sec, excluding I/O = %d sec", sw1.getTime() / 1000, (sw1.getTime() - sw2.getTime()) / 1000));
}
public class MyTask<H extends CsvFileHeader, R extends CsvFileRow<H>> implements Runnable {
private final byte[] m_buffer;
private final String m_name;
private final CoordinateCollector m_coordinateCollector;
private final Set<Long> m_allCoordinates;
private final Class<H> m_headerClass;
private final Class<R> m_rowClass;
public MyTask(File file, CoordinateCollector coordinateCollector, Set<Long> allCoordinates,
Class<H> headerClass, Class<R> rowClass) throws IOException {
m_coordinateCollector = coordinateCollector;
m_allCoordinates = allCoordinates;
m_headerClass = headerClass;
m_rowClass = rowClass;
m_name = file.getName();
m_buffer = Files.toByteArray(file);
}
@Override
public void run() {
try {
m_coordinateCollector.collect(m_name, m_buffer, m_allCoordinates, m_headerClass, m_rowClass);
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
結果を以下で見つけてください(繰り返し部分を省略するために出力を少し変更しました):
Max concurrent threads = 4
Total file count = 84
Total lines = 56395333
Total good lines = 35119231
Total coordinates = 987045
Overall elapsed time = 274 sec, excluding I/O = 266 sec
Max concurrent threads = 6
Overall elapsed time = 218 sec, excluding I/O = 209 sec
Max concurrent threads = 7
Overall elapsed time = 209 sec, excluding I/O = 199 sec
Max concurrent threads = 8
Overall elapsed time = 201 sec, excluding I/O = 192 sec
Max concurrent threads = 9
Overall elapsed time = 198 sec, excluding I/O = 186 sec
独自の結論を自由に引き出すことができますが、私の具体的なケースでは、ハイパースレッディングによってパフォーマンスが向上するということです。また、6つのワーカースレッドを持つことは、このタスクと私のマシンにとって正しい選択のようです。