Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我应该使用Java中的哪个线程池?_Java_Scala_Threadpool_Actor_Akka - Fatal编程技术网

我应该使用Java中的哪个线程池?

我应该使用Java中的哪个线程池?,java,scala,threadpool,actor,akka,Java,Scala,Threadpool,Actor,Akka,有大量的任务。 每个任务都属于一个组。要求是每组任务应该像在单个线程中执行一样串行执行,并且在多核(或多cpu)环境中吞吐量应该最大化。注意:还有大量的组与任务数量成比例 最简单的解决方案是使用ThreadPoolExecutor和synchronize(或lock)。但是,线程会相互阻塞,吞吐量没有最大化 还有更好的主意吗?或者是否存在满足要求的第三方库?我建议使用任务队列: 对于已创建的每组任务,创建一个队列并将该组中的所有任务插入其中 现在,所有队列都可以并行执行,而一个队列中的任务可以

有大量的任务。 每个任务都属于一个组。要求是每组任务应该像在单个线程中执行一样串行执行,并且在多核(或多cpu)环境中吞吐量应该最大化。注意:还有大量的组与任务数量成比例


最简单的解决方案是使用ThreadPoolExecutor和synchronize(或lock)。但是,线程会相互阻塞,吞吐量没有最大化


还有更好的主意吗?或者是否存在满足要求的第三方库?

我建议使用任务队列:

  • 对于已创建的每组任务,创建一个队列并将该组中的所有任务插入其中
  • 现在,所有队列都可以并行执行,而一个队列中的任务可以串行执行

快速的google搜索表明JavaAPI本身没有任务/线程队列。然而,有许多教程可用于编写一个。如果你知道一些,每个人都可以随意列出好的教程/实现:

我基本上同意Dave的答案,但是如果你需要在所有“组”之间划分CPU时间,即所有任务组应该并行进行,你可能会发现这种构造很有用(使用移除作为“锁”)。这在我的情况下效果很好,但我认为它会占用更多内存):

其中,
复杂比较器

class SophisticatedComparator implements Comparator<MyQueue<Runnable>> {
    public int compare(MyQueue<Runnable> o1, MyQueue<Runnable> o2){
        int diff = o2.size() - o1.size();
        if(diff==0){
             //This is crucial. You must assign unique ids to your 
             //Subqueue and break the equality if they happen to have same size.
             //Otherwise your queues will disappear...
             return o1.id - o2.id;
        }
        return diff;
    }
 }
类复杂比较器实现比较器{
公共整数比较(MyQueue o1,MyQueue o2){
int diff=o2.size()-o1.size();
如果(差异==0){
//这是至关重要的。您必须为您的应用程序分配唯一的ID
//子队列,如果它们恰好具有相同的大小,则打破相等。
//否则您的队列将消失。。。
返回o1.id-o2.id;
}
返回差;
}
}

一种简单的方法是将所有组任务“连接”到一个超级任务中,从而使子任务连续运行。但这可能会导致其他组延迟,除非其他组完全完成并在线程池中留出一些空间,否则这些组不会启动

作为一种选择,考虑链接组的任务。下面的代码对此进行了说明:

public class MultiSerialExecutor {
    private final ExecutorService executor;

    public MultiSerialExecutor(int maxNumThreads) {
        executor = Executors.newFixedThreadPool(maxNumThreads);
    }

    public void addTaskSequence(List<Runnable> tasks) {
        executor.execute(new TaskChain(tasks));
    }

    private void shutdown() {
        executor.shutdown();
    }

    private class TaskChain implements Runnable {
        private List<Runnable> seq;
        private int ind;

        public TaskChain(List<Runnable> seq) {
            this.seq = seq;
        }

        @Override
        public void run() {
            seq.get(ind++).run(); //NOTE: No special error handling
            if (ind < seq.size())
                executor.execute(this);
        }       
    }
公共类MultiSerialExecutor{
私人最终执行人服务执行人;
公共MultiSerialExecutor(int-maxNumThreads){
executor=Executors.newFixedThreadPool(maxNumThreads);
}
public void addTaskSequence(列出任务){
executor.execute(新任务链(任务));
}
私有无效关闭(){
executor.shutdown();
}
私有类TaskChain实现可运行{
私人名单如下;
私人工业;
公共任务链(列表如下){
this.seq=seq;
}
@凌驾
公开募捐{
seq.get(ind++).run();//注意:没有特殊的错误处理
如果(ind
优点是没有使用额外的资源(线程/队列),并且任务的粒度比naive方法中的粒度要好。缺点是所有组的任务都应该提前知道

--编辑--


要使此解决方案具有通用性和完整性,您可能需要决定错误处理(即即使发生错误,链是否继续),并且最好实现ExecutorService,并将所有调用委托给底层执行者。

Actor也是此指定类型问题的另一个解决方案。
Scala有actors,也有Java,由AKKA提供。

我遇到了一个与您类似的问题,我使用了一个与执行器一起工作的
ExecutorCompletionService
来完成任务集合。 以下是java.util.concurrent API的摘录,因为Java7:

假设您有一组用于某个问题的解算器,每个解算器返回某种类型的值Result,并希望同时运行它们,在某些方法使用(Result r)中处理每个返回非空值的解算器的结果。您可以这样写:

void solve(执行器e、集合解算器)
抛出InterruptedException、ExecutionException{
CompletionService ecs=新的ExecutionCompletionService(e);
for(可调用的s:解算器)
ecs.提交;
int n=solvers.size();
对于(int i=0;i
因此,在您的场景中,每个任务都是一个可调用的
,任务将分组在
集合中

参考:

“但是,线程会相互阻塞,吞吐量不会最大化。”。您的意思是,单个任务正在访问共享数据结构或资源,这是争用的原因吗?您是否提前知道组的所有任务?这在选择解决方案时很重要(队列与无队列)谢谢Dave。如果有大量的组,那么线程数量将达到极限。@James不一定。仅仅因为你有n个组并不意味着你需要创建n个线程来执行它们。只要创建你认为合适的线程数量,它们就会以循环方式或串行方式处理队列。+1任务队列允许您使用任何适合您需要的调度算法。看起来您正在实现一个线程池。为什么不使用标准ThreadPoolExecutor加上我的解决方案中的一些额外功能呢?我的解决方案不需要队列和同步。@Eyal:如果可以按顺序使用任务组,我同意您的看法但是,如果它们必须并行使用,这是必要的。在我的解决方案中,组是并行执行的,每个组都是串行执行的,就像在您的解决方案中一样
ConcurrentSkipListSet<MyQueue<Runnable>> sophisticatedQueue = 
    new ConcurrentSkipListSet(new SophisticatedComparator());
class SophisticatedComparator implements Comparator<MyQueue<Runnable>> {
    public int compare(MyQueue<Runnable> o1, MyQueue<Runnable> o2){
        int diff = o2.size() - o1.size();
        if(diff==0){
             //This is crucial. You must assign unique ids to your 
             //Subqueue and break the equality if they happen to have same size.
             //Otherwise your queues will disappear...
             return o1.id - o2.id;
        }
        return diff;
    }
 }
public class MultiSerialExecutor {
    private final ExecutorService executor;

    public MultiSerialExecutor(int maxNumThreads) {
        executor = Executors.newFixedThreadPool(maxNumThreads);
    }

    public void addTaskSequence(List<Runnable> tasks) {
        executor.execute(new TaskChain(tasks));
    }

    private void shutdown() {
        executor.shutdown();
    }

    private class TaskChain implements Runnable {
        private List<Runnable> seq;
        private int ind;

        public TaskChain(List<Runnable> seq) {
            this.seq = seq;
        }

        @Override
        public void run() {
            seq.get(ind++).run(); //NOTE: No special error handling
            if (ind < seq.size())
                executor.execute(this);
        }       
    }
void solve(Executor e, Collection<Callable<Result>> solvers)
        throws InterruptedException, ExecutionException {
    CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
    for (Callable<Result> s : solvers)
        ecs.submit(s);
    int n = solvers.size();
    for (int i = 0; i < n; ++i) {
        Result r = ecs.take().get();
        if (r != null)
            use(r);
    }
}