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