gpt4 book ai didi

java - 将 ExecutorService 与要执行的任务树一起使用

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:26:27 24 4
gpt4 key购买 nike

我们遇到了一些问题。 :)

我们要保证任何时候只有N个线程在做后台任务。为此,我们使用了一个固定的线程池执行器。它似乎工作正常。

然后我们发现了一个问题。假设您有一个使用执行器执行一些并行工作的类,然后它在执行器线程中调用其他一些类,该线程也执行一些并行工作,打算等待它。这是发生了什么:

  • 主线程调用一级方法。
  • 该方法认为它可以并行化为 16 个任务并拆分其工作。
  • 16个任务提交给执行者。
  • 主线程开始等待其任务完成。
  • 假设有四个线程可用,前四个任务各自被拾取并运行。所以队列中还剩下 12 个任务。
  • 现在,其中一个任务调用其他方法。
  • 这种新方法认为它可以并行化为 2 个任务。假设这是并行合并排序的第一步或类似的事情。
  • 2个任务被提交给执行者。
  • 此线程现在开始等待其任务完成。

呃哦。所以此时,所有四个线程现在都在等待任务完成,但它们协同阻止实际运行这些任务的执行程序。

此问题的解决方案 1 如下:在向执行程序提交新任务时,如果我们已经在运行所有线程,并且我们已经在其中一个执行程序线程上运行,则以内联方式运行任务。这在 10 个月内运行良好,但现在我们遇到了问题。如果它提交的新任务仍然相对较大,那么您可能会遇到这样一种情况,即新任务会阻止该方法将其他任务添加到队列中,否则其他工作线程将能够拾取这些任务。因此,当线程正在处理内联工作时,您会遇到巨大的延迟。

是否有更好的解决方案来解决执行潜在无界树的后台任务的核心问题?我知道 .NET 等同于执行程序服务具有某种内置的从队列中窃取的能力,从而防止发生原始死锁问题,据我所知这是一个理想的解决方案。但是在 Java 土地上呢?

最佳答案

Java 7 有一个 ForkJoinPool 的概念,它允许一个任务通过将另一个任务提交给同一个执行器来“ fork ”另一个任务。然后为其提供稍后尝试“帮助加入”该任务的选项,方法是如果该任务尚未运行则尝试运行它。

我相信在 Java 6 中可以通过将 ExecutorFutureTask 简单组合来完成同样的事情。像这样:

public class Fib implements Callable<Integer> {
int n;
Executor exec;

Fib(final int n, final Executor exec) {
this.n = n;
this.exec = exec;
}

/**
* {@inheritDoc}
*/
@Override
public Integer call() throws Exception {
if (n == 0 || n == 1) {
return n;
}

//Divide the problem
final Fib n1 = new Fib(n - 1, exec);
final Fib n2 = new Fib(n - 2, exec);

//FutureTask only allows run to complete once
final FutureTask<Integer> n2Task = new FutureTask<Integer>(n2);
//Ask the Executor for help
exec.execute(n2Task);

//Do half the work ourselves
final int partialResult = n1.call();

//Do the other half of the work if the Executor hasn't
n2Task.run();

//Return the combined result
return partialResult + n2Task.get();
}

}

关于java - 将 ExecutorService 与要执行的任务树一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5254294/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com