问题描述
我想知道我可以运行的最佳线程数。通常,这等于 Runtime.getRuntime()。availableProcessors()
。
I would like to know the optimal number of threads I can run. Normally, this equals to Runtime.getRuntime().availableProcessors()
.
但是,在支持超线程的CPU上,返回的数字是两倍。现在,对于某些任务,超线程是好的,但对于其他任务,它什么都不做。在我的情况下,我怀疑,它什么都不做,所以我想知道我是否必须将 Runtime.getRuntime()。availableProcessors()
返回的数字除以二。
However, the returned number is twice as high on a CPU supporting hyper threading. Now, for some tasks hyper threading is good, but for others it does nothing. In my case, I suspect, it does nothing and so I wish to know whether I have to divide the number returned by Runtime.getRuntime().availableProcessors()
in two.
为此,我必须推断出CPU是否是超线程。因此我的问题 - 我怎么能用Java做?
For that I have to deduce whether the CPU is hyper threading. Hence my question - how can I do it in Java?
谢谢。
EDIT
好的,我已经对我的代码进行了基准测试。这是我的环境:
OK, I have benchmarked my code. Here is my environment:
- 联想ThinkPad W510(即带有4核和超线程的i7 CPU),16G内存
- Windows 7
- 84个压缩CSV文件,压缩大小从105M到16M
- 所有文件都是逐个读取的主线程 - 没有多线程访问HD。
- 每个CSV文件行包含一些数据,这些数据被解析,快速无上下文测试确定该行是否相关。
- 每个相关的行包含两个双打(代表经度和纬度,对于好奇的人),它们被强制转换为单个
Long
,然后存储在共享哈希集中。
- Lenovo ThinkPad W510 (i.e. i7 CPU with 4 cores and hyperthreading), 16G of RAM
- Windows 7
- 84 zipped CSV files with zipped sizes ranging from 105M to 16M
- All the files are read one by one in the main thread - no multithreading access to the HD.
- Each CSV file row contains some data, which is parsed and a fast context-free test determines whether the row is relevant.
- Each relevant row contains two doubles (representing longitude and latitude, for the curious), which are coerced into a single
Long
, which is then stored in a shared hash set.
因此工作线程不会从HD中读取任何内容,但它们会通过解压缩和解析来占用自己内容(使用库)。
Thus the worker threads do not read anything from the HD, but they do occupy themselves with unzipping and parsing the contents (using the opencsv library).
下面是代码,没有枯燥的细节:
Below is the code, w/o the boring details:
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.
}
}
}
请在下面找到结果(我稍微更改了输出以省略重复部分):
Please, find below the results (I have slightly changed the output to omit the repeating parts):
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个工作线程似乎是此任务和我的机器的正确选择。
You are free to draw your own conclusions, but mine is that hyperthreading does improve the performance in my concrete case. Also, having 6 worker threads seems to be the right choice for this task and my machine.
推荐答案
对于 Windows
,如果逻辑核心数高于核心数量,你有已启用。阅读更多相关信息。
For Windows
, if the number of logical cores is higher than the number of cores, you have hyper-threading
enabled. Read more about it here.
您可以使用 wmic
来查找此信息:
You can use wmic
to find this information:
C:\WINDOWS\system32>wmic CPU Get NumberOfCores,NumberOfLogicalProcessors /Format:List
NumberOfCores=4
NumberOfLogicalProcessors=8
因此,我的系统超线程
。逻辑处理器的数量是核心的两倍。
Hence, my system has hyper-threading
. The amount of logical processors is double the cores.
但您甚至可能不需要知道。 Runtime.getRuntime()。availableProcessors()
已经返回逻辑处理器的数量。
But you may not even need to know. Runtime.getRuntime().availableProcessors()
already returns the amount of logical processors.
获取完整示例物理核心数(仅限 Windows
):
A full example on getting the physical cores count (Windows
only):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class PhysicalCores
{
public static void main(String[] arguments) throws IOException, InterruptedException
{
int physicalNumberOfCores = getPhysicalNumberOfCores();
System.out.println(physicalNumberOfCores);
}
private static int getPhysicalNumberOfCores() throws IOException, InterruptedException
{
ProcessBuilder processBuilder = new ProcessBuilder("wmic", "CPU", "Get", "NumberOfCores");
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
String processOutput = getProcessOutput(process);
String[] lines = processOutput.split(System.lineSeparator());
return Integer.parseInt(lines[2]);
}
private static String getProcessOutput(Process process) throws IOException, InterruptedException
{
StringBuilder processOutput = new StringBuilder();
try (BufferedReader processOutputReader = new BufferedReader(
new InputStreamReader(process.getInputStream())))
{
String readLine;
while ((readLine = processOutputReader.readLine()) != null)
{
processOutput.append(readLine);
processOutput.append(System.lineSeparator());
}
process.waitFor();
}
return processOutput.toString().trim();
}
}
这篇关于如果CPU是超线程,是否可以检查Java?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!