强制多个线程在可用时使用多个 CPU

我正在编写一个Java程序,由于它所做的性质,它使用了大量的CPU。但是,它中的很多都可以并行运行,并且我已经使我的程序成为多线程的。当我运行它时,它似乎只使用一个CPU,直到它需要更多,然后使用另一个CPU - 在Java中我可以做些什么来强制不同的线程在不同的内核/ CPU上运行?


答案 1

在 Java 中,有两种基本的多线程方法。使用这些方法创建的每个逻辑任务都应在需要时和可用时在新的内核上运行。

方法一:定义一个 Runnable 或 Thread 对象(可以在构造函数中采用 Runnable),并使用 Thread.start() 方法启动它。它将在操作系统赋予它的任何核心上执行 - 通常是负载较少的内核。

教程:定义和启动线程

方法二:定义实现 Runnable(如果它们不返回值)或 Callable(如果它们返回值)接口的对象,其中包含您的处理代码。将这些任务作为任务从 java.util.concurrent 包传递到 ExecutorService。java.util.concurrent.Executors 类有一堆方法来创建标准的、有用的 ExecutorServices。链接到执行器教程。

从个人经验来看,执行器固定和缓存线程池非常好,尽管您需要调整线程计数。Runtime.getRuntime().availableProcessors() 可以在运行时用于计算可用内核的次数。应用程序完成后,您需要关闭线程池,否则应用程序不会退出,因为 ThreadPool 线程保持运行。

获得良好的多核性能有时很棘手,而且充满了陷阱:

  • 并行运行时,磁盘 I/O 速度会降低很多。一次只能有一个线程执行磁盘读/写操作。
  • 对象同步为多线程操作提供了安全性,但会减慢工作速度。
  • 如果任务太琐碎(工作位太小,执行速度快),在执行器服务中管理它们的开销成本会高于您从多个内核中获得的成本。
  • 创建新的 Thread 对象的速度很慢。如果可能,执行器服务将尝试重用现有线程。
  • 当多个线程处理某事时,会发生各种疯狂的事情。保持系统简单,并尝试使任务在逻辑上不同且非交互。

另一个问题是:控制工作是困难的!一个好的做法是让一个管理器线程创建和提交任务,然后使用几个具有工作队列的工作线程(使用 ExecutorService)。

我只是在这里触及关键点 - 多线程编程被许多专家认为是最困难的编程主题之一。它是非直观的,复杂的,抽象往往是弱的。


编辑 -- 使用 ExecutorService 的示例:

public class TaskThreader {
    class DoStuff implements Callable {
       Object in;
       public Object call(){
         in = doStep1(in);
         in = doStep2(in);
         in = doStep3(in); 
         return in;
       }
       public DoStuff(Object input){
          in = input;
       }
    }

    public abstract Object doStep1(Object input);    
    public abstract Object doStep2(Object input);    
    public abstract Object doStep3(Object input);    

    public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        ArrayList<Callable> tasks = new ArrayList<Callable>();
        for(Object input : inputs){
           tasks.add(new DoStuff(input));
        }
        List<Future> results = exec.invokeAll(tasks);
        exec.shutdown();
        for(Future f : results) {
           write(f.get());
        }
    }
}

答案 2

当我运行它时,它似乎只使用一个CPU,直到它需要更多,然后使用另一个CPU - 在Java中我可以做些什么来强制不同的线程在不同的内核/ CPU上运行?

我将问题的这一部分解释为,这意味着您已经解决了使应用程序具有多线程功能的问题。尽管如此,它并没有立即开始使用多个内核。

答案是“有没有办法强迫......”是(AFAIK)不是直接的。您的 JVM 和/或主机操作系统决定使用多少个“本机”线程,以及如何将这些线程映射到物理处理器。您确实有一些调整选项。例如,我发现这个页面讨论了如何在Solaris上调整Java线程。本页讨论了可能降低多线程应用程序速度的其他因素。


推荐