递归并发

时间:2013-02-26 08:14:13

标签: java recursion concurrency

我有以下函数,伪代码:

Result calc(Data data) {
  if (data.isFinal()) {
    return new Result(data); // This is the actual lengthy calculation
  } else {
    List<Result> results = new ArrayList<Result>();
    for (int i=0; i<data.numOfSubTasks(); ++i) {
      results.add(calc(data.subTask(i));
    }
    return new Result(results); // merge all results in to a single result
  }
}

我希望使用固定数量的线程并行化它。

我的第一次尝试是:

ExecutorService executorService = Executors.newFixedThreadPool(numOfThreads);

Result calc(Data data) {
  if (data.isFinal()) {
    return new Result(data); // This is the actual lengthy calculation
  } else {
    List<Result> results = new ArrayList<Result>();
    List<Callable<Void>> callables = new ArrayList<Callable<Void>>();
    for (int i=0; i<data.numOfSubTasks(); ++i) {
      callables.add(new Callable<Void>() {
        public Void call() {
         results.add(calc(data.subTask(i));
        }
      });
    }
    executorService.invokeAll(callables);  // wait for all sub-tasks to complete
    return new Result(results); // merge all results in to a single result
  }
}

然而,这很快就陷入了僵局,因为,当顶级递归级别等待所有线程完成时,内部级别也会等待线程变为可用...

如何在没有死锁的情况下有效地并行化我的程序?

2 个答案:

答案 0 :(得分:5)

将ThreadPoolExecutor用于具有依赖关系的任务时,您的问题是一个常见的设计问题。

我看到两个选项:

1)确保以自下而上的顺序提交任务,以便您永远不会有依赖于尚未启动的任务的正在运行的任务。

2)使用“直接切换”策略(参见ThreadPoolExecutor文档):

ThreadPoolExecutor executor = new ThreadPoolExecutor(poolSize, poolSize, 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
executor.setRejectedExecutionHandler(new CallerRunsPolicy());

这个想法是使用同步队列,以便任务永远不会在真正的队列中等待。拒绝处理程序负责处理没有可用线程的任务。使用此特定处理程序,提交程序线程将运行被拒绝的任务。

此执行程序配置可确保永远不会拒绝任务,并且您永远不会因任务间依赖性而导致死锁。

答案 1 :(得分:0)

你应该分两个阶段分开你的方法:

  1. 创建所有树,直到data.isFinal()== true
  2. 递归收集结果(仅当合并不产生其他操作/调用时才可能)
  3. 为此,您可以使用[Futures][1]将结果设为异步。表示calc的所有结果都是Future [Result]类型。

    立即返回Future将释放当前线程并为其他线程的处理留出空间。通过收集结果(新结果(结果)),您应该等待所有结果准备就绪(ScatterGather-Pattern,您可以使用信号量等待所有结果)。集合本身将走在一棵树上,检查(或等待结果到达)将在一个线程中发生。

    总体而言,您构建了一个Futures树,用于收集结果并仅执行线程池中的“昂贵”操作。