【问题标题】:java multithreading not utilizing all coresjava多线程不使用所有内核
【发布时间】:2012-08-18 19:00:01
【问题描述】:

我有一个多线程程序,它似乎并没有真正利用我机器上的所有内核。这是代码,任何输入都将受到高度赞赏。

主类

public class MainClass{
 public static void main(String [] args){
  Work work=new Work();
  work.doIt();
 }
}

第二个类创建任务并交给ExecutorService,这里是伪代码

public class Work{
 public void doIt() throws InterrputedException, Exception{
  map=get some data and put it in the map;
  ArrayList<Future<Integer>> list=new ArrayList<Future<Integer>>();
  ArrayList<WorkCallable>jobs=new ArrayList<WorkCallable>();
  for each entry in the map;
    jobs.add(new WorkCallable(entry);
  int numCores=Runtime.getRuntime().availableProcessors();
  ExecutorService executor=Executors.newFixedThreadPool(numCores);
  int size=jobs.size();
  for(int i=0;i<size;i++){
    Callable<Integer> worker=jobs.get(i);
    Future<Integer> submit=executor.submit(worker);
    list.add(submit);
  }
  executor.shutdown();
  while(!executor.isTerminated()) {}
  do something with the returned data;
}
}

可调用类

public class WorkCallable implements Callable<Integer>{
 @Override
 public Integer call() throws Exception{
   Properties props=new Properties();
   props.put("annotators", "tokenize, ssplit, pos");
   StanfordCoreNLP pipeline=new StanfordCoreNLP(props);
   for(String id:entry.keySet()){
   Annotation document=new Annotation(entry.get(id));
   pipeline.annotate(document);

   process the data;
   return an integer value;
 }
}

问题是,当我检查有多少线程正在运行时,我发现只有很少,而且执行器似乎没有利用理想的内核!

我希望描述清楚。

更新

  • 使用的库是 StanfordCoreNLP 包,用于处理作为 documentID 及其内容的 Map 传递给 Callable 对象的文本。处理数据不是问题,因为我在不包含 StanfordCoreNLP 库的情况下工作得很好。换句话说,文档的浅层处理可以正常工作并利用所有内核。但是当我包含这个包时它没有。

【问题讨论】:

  • 您忙于等待while(!executor.isTerminated()) {} 需要一个核心。你不应该那样做。有awaitTermination 供您使用。顺便说一句,“非常少”的数量究竟是多少,你知道你拥有多少个核心?更好的是,System.out.println(Runtime.getRuntime().availableProcessors()) 打印什么?
  • 描述也不是很清楚。 “加载一些库”和“处理数据”听起来都像是潜在的同步操作,这可能会导致所有线程退出运行状态,但只有一个线程处于运行状态。
  • 感谢您的 cmets Marko 和 mazaneicha。我同意加载库可能是个问题。

标签: java multithreading nlp executorservice stanford-nlp


【解决方案1】:

如果您使用的是 Windows,那么 JVM 将委托线程调度 NT 内核。 POSIX 类型的操作系统直接将操作系统线程映射到 JVM 并协同调度。

但是,无论发生什么情况,您都无法确保线程在内核/处理器之间均匀分配。当您启动第 4 个线程时,操作系统上的其他东西可能正在核心 4 上运行,因此它可能会被安排到另一个核心。或者调度程序可以决定将它们堆叠在同一个核心上。

【讨论】:

  • 谢谢丹。好吧,即使核心 4 上正在运行的东西应该显示为一个正在运行的进程,而它并没有,并且核心 id 就 top 和 htop 而言是理想的。
【解决方案2】:

此时,根据您提供的信息,我怀疑线程之间存在一些争用,因此很可能某些线程被阻塞/等待。要验证这一点,您可以使用 JVisual VM 并进行线程转储(Jconsole 也是一个选项)。 JVisual VM 是监控 java 应用程序的实用程序,并附带 JDK。如果您在此之前没有使用过它,那将是您花时间学习它的好投资,因为它非常有用且易于使用。

See Here for JVisualVM

  1. 使用 JVisual VM Take Thread dump 连接到您的程序。
  2. 它会在那个时候为您提供程序中的线程状态 时间实例,如果存在争用和/或阻塞,则很容易 现场使用线程转储。
  3. 请随意将其粘贴到此处,以防您看不清是什么 发生在线程转储中,尽管有很多资源 你了解网络上的线程转储

另一方面,正如@Marko 指出的那样,您可以更有效地处理执行程序关闭,我会说 ExecutorCompletionService 符合您的要求并使代码更加优雅和易于阅读。 Check here for ExecutorCompletionService 一旦你发现空闲内核可能是你可以重构使用 ECS。

【讨论】:

  • 非常感谢苏迪您的详细评论。我会检查您发布的资源并返回更多详细信息。
猜你喜欢
  • 1970-01-01
  • 2020-10-15
  • 2011-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-08
  • 2015-07-25
  • 1970-01-01
相关资源
最近更新 更多