有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java中一种多线程负载平衡线程池

我正在寻找一个负载平衡的线程池,到目前为止还没有成功。(不确定负载平衡是否是正确的措辞)。 让我解释一下我试图实现的目标

第1部分: 我有工作,有8到10个单项任务。在6核CPU上,我让8个线程并行处理这些任务,这似乎提供了最佳性能。当一项任务准备就绪时,另一项任务就可以开始了。一旦这十项任务全部完成,整个工作就完成了。通常一项工作在30到60秒内完成

第二部分: 不幸的是,有时这项工作需要两个多小时。这是正确的,因为需要计算的数据量很大。 糟糕的是,当job1运行时(假设所有线程的持续时间相同),没有其他作业可以启动,因为它使用所有线程

我的第一个想法是: 具有12个线程,最多允许并行执行三个作业。 但是:这意味着,当只有一个作业时,cou还没有完全解除

我正在寻找一种解决方案,在没有其他作业的情况下,为作业1提供完整的CPU电源。但是当另一个作业在运行时需要启动另一个作业时,我希望分配给这两个作业的CPU功率。当第三个或第四个作业出现时,我希望cpu功率公平分配给所有四个作业

我很感激你的回答

提前谢谢


共 (3) 个答案

  1. # 1 楼答案

    正如Kanaga所建议的,最简单的方法是超额订阅CPU,但每个CPU启动8个线程。竞争可能会带来一些开销,但如果您只处理一个作业,它将充分利用CPU。操作系统将为每个线程分配时间

    你的“第一个想法”也会奏效。如果空闲线程没有实际执行任务,那么它们不会从8个工作线程获取资源。但是,当有多个作业在运行时,这并不能均匀地分配cpu资源

    您是否有可以测试这些不同管道的设置,以了解它们对您的性能如何

  2. # 2 楼答案

    一种可能是将标准ThreadPoolExecutor与不同类型的任务队列一起使用

    public class TaskRunner {
      private static class PriorityRunnable implements Runnable,
                Comparable<PriorityRunnable> {
        private Runnable theRunnable;
        private int priority = 0;
        public PriorityRunnable(Runnable r, int priority) {
          this.theRunnable = r;
          this.priority = priority;
        }
    
        public int getPriority() {
          return priority;
        }
    
        public void run() {
          theRunnable.run();
        }
    
        public int compareTo(PriorityRunnable that) {
          return this.priority - that.priority;
        }
      }
    
      private BlockingQueue<Runnable> taskQueue = new PriorityBlockingQueue<Runnable>();
    
      private ThreadPoolExecutor exec = new ThreadPoolExecutor(8, 8, 0L,
                TimeUnit.MILLISECONDS, taskQueue);
    
      public void runTasks(Runnable... tasks) {
        int priority = 0;
        Runnable nextTask = taskQueue.peek();
        if(nextTask instanceof PriorityRunnable) {
          priority = ((PriorityRunnable)nextTask).getPriority() + 1;
        }
        for(Runnable t : tasks) {
          exec.execute(new PriorityRunnable(t, priority));
          priority += 100;
        }
      }
    }
    

    这里的想法是,当你有一份新工作时,你会打电话给他

    taskRunner.runTasks(jobTask1, jobTask2, jobTask3);
    

    它将以这样一种方式对任务进行排队:它们与队列中的任何现有任务(如果有的话)巧妙地交织在一起。假设有一个作业排队,其任务的优先级号为j1t1=3、j1t2=103和j1t3=203。在没有其他作业的情况下,这些任务将尽快一个接一个地执行。但是,如果您提交了另一个包含三个任务的作业,这些任务将被分配优先级号j2t1=4、j2t2=104和j2t3=204,这意味着队列现在看起来像

    j1t1,j2t1,j1t2,j2

    但是,这并不完美,因为如果所有线程当前都在工作(在作业1的任务上),那么作业2的第一个任务在作业1的一个任务完成之前无法启动(除非有某种外部方法让您检测到这一点,并中断作业1的一些任务并重新排队)。让事情变得更公平的最简单方法是将运行时间较长的任务分解为较小的部分,并将它们作为单独的任务进行排队-您需要达到这样一个点,即每个单独的作业所涉及的任务比池中的线程多,因此,一些任务总是从队列中开始,而不是直接分配给线程(如果有空闲线程,那么exec.execute()将任务直接传递给线程,而根本不经过队列)