以负载平衡的方式在4个线程上分配10个无限作业(Java)

Geo*_*met 6 java concurrency multithreading threadpool

我有10个计算工作需要(接近)无限时间.例如:计算PI的下一个数字,解决 NP-hard约束满足问题等.

我有4个线程(这样一个线程池4个线程的机器上8个内核,所以我有一些核心留给避免活锁的机器和过程).

使用Java 8,如何在这4个线程中分配这10个作业?

这是一个坏主意:

ExecutorService es = Executors.newFixedThreadPool(4);
for (Job j : jobs) {
    es.submit(j);
}
Run Code Online (Sandbox Code Playgroud)

因为4个工作将开始,但没有一个工作将完成所以工作5-10永远不会开始.

如果我照顾例如10分钟,我希望每个工作都运行大约4分钟.20分钟后,每项工作已经运行了大约8分钟,等等.处理这种情况的典型模式是什么?(如果需要,我可以在预设的时间后实现一种暂停计算的方法.)

And*_*gin 6

在你的十个工作中,在四个线程之间分配十个作业的任务和仅使用四个CPU的任务(我在这里使用CPU作为核心的同义词)有点不同.

四个线程

将线程数限制为四并不能保证它们会坚持使用四个CPU而不会使用其他CPU.允许操作系统根据需要在所有可用CPU之间对线程进行洗牌.您唯一可以保证的是,您的程序将无法利用所有CPU资源的50%以上(假设您有8个CPU).

但你不可能设法利用这50%.尽管您的工作主要是面向CPU,但他们仍有可能不时需要读取和写入内存.当一个线程错过这些读/写上的缓存并等待数据传递给处理器时,该处理器将该线程置于保持状态并可以在另一个线程中完成一些工作.在你的情况下,它将无所事事,只是闲置,直到数据到达.因此,您的CPU很可能未得到充分利用.

如果您决定采用这种方法,您需要将工作分成小任务并将其提供给执行者,正如@James Large所说.您可以使用WorkStealingPool四个线程(如@Alexey Soshin建议的那样),或创建一个包含十个线程的池,并使用Semaphore四个允许和公平设置true.在后一种情况下,您的线程必须使用循环,在每次迭代开始时获取许可并在结束时释放它们.每次迭代都代表了一小部分工作.

四个CPU

有一些机制可以指定特定的CPU来处理您的任务.

在Linux的进程级别,您可以使用特殊命令将进程绑定到特定的CPU.这将允许您创建十个线程并让操作系统在四个CPU上完成所有平衡.

在线程级别,您可以尝试OpenHFT中的Java Affinity库.它允许在Java代码中将线程绑定到CPU.问题是没有提醒就不能在四个CPU之间划分十个线程,因此很难平衡它们.