是否可以在Java中检查CPU是否是超线程的?

2024-05-24

我想知道可以运行的最佳线程数。通常,这等于Runtime.getRuntime().availableProcessors().

但是,在支持超线程的 CPU 上,返回的数字是其两倍。现在,对于某些任务来说,超线程是好的,但对于其他任务来说,它没有任何作用。就我而言,我怀疑它什么也没做,所以我想知道是否必须将返回的数字除以Runtime.getRuntime().availableProcessors()成两半。

为此,我必须推断 CPU 是否是超线程。因此我的问题是——我怎样才能用Java做到这一点?

Thanks.

EDIT

好的,我已经对我的代码进行了基准测试。这是我的环境:

  • Lenovo ThinkPad W510(即 4 核和超线程的 i7 CPU),16G RAM
  • Windows 7的
  • 84 个压缩的 CSV 文件,压缩大小从 105M 到 16M
  • 所有文件都在主线程中一一读取 - 没有对硬盘的多线程访问。
  • 每个 CSV 文件行都包含一些数据,这些数据将被解析,并通过快速的上下文无关测试确定该行是否相关。
  • 每个相关行包含两个双精度数(代表经度和纬度,为了好奇),它们被强制转换为一个Long,然后存储在共享哈希集中。

因此,工作线程不会从 HD 读取任何内容,但它们确实会忙于解压缩和解析内容(使用opencsv http://opencsv.sourceforge.net/图书馆)。

下面是代码,没有无聊的细节:

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 个工作线程似乎是正确的选择。


不幸的是,这在 java 中是不可能的。如果您知道该应用程序将在现代 Linux 变体上运行,您可以读取文件 /proc/cpuinfo 并推断 HT 是否已启用。

读取此命令的输出可以解决问题:

grep -i "physical id" /proc/cpuinfo | sort -u | wc -l
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以在Java中检查CPU是否是超线程的? 的相关文章

随机推荐