ExecutorCompletionService?如果我们有 invokeAll 为什么需要一个? [英] ExecutorCompletionService? Why do need one if we have invokeAll?

查看:27
本文介绍了ExecutorCompletionService?如果我们有 invokeAll 为什么需要一个?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我们使用 ExecutorCompletionService,我们可以提交一个一系列任务作为 Callable 并获得与 CompletionService 交互的结果作为 queue.

If we use an ExecutorCompletionService we can submit a series of tasks as Callables and get the result interacting with the CompletionService as a queue.

但是还有ExecutorServiceinvokeAll,它接受一个Collection的任务,我们得到一个Future检索结果.

But there is also the invokeAll of ExecutorService that accepts a Collection of tasks and we get a list of Future to retrieve the results.

据我所知,使用一个或另一个没有任何好处(除了我们使用 invokeAll 避免了 for 循环,我们将有submit 任务到 CompletionService),本质上它们是相同的想法,但略有不同.

As far as I can tell, there is no benefit in using one or over the other (except that we avoid a for loop using an invokeAll that we would have to submit the tasks to the CompletionService) and essentially they are the same idea with a slight difference.

那么为什么有两种不同的方式来提交一系列任务呢?我是否纠正了性能方面它们是等效的?是否存在一种比另一种更合适的情况?我想不出一个.

So why are there 2 different ways to submit a series of tasks? Am I correct that performance wise they are equivalent? Is there a case that one is more suitable than the other? I can't think of one.

推荐答案

使用 ExecutorCompletionService.poll/take,您将在 Future 完成时收到它们,在完成顺序(或多或少).使用ExecutorService.invokeAll,你没有这个权力;您要么阻塞直到全部完成,要么指定一个超时时间,在此之后取消未完成的部分.

Using a ExecutorCompletionService.poll/take, you are receiving the Futures as they finish, in completion order (more or less). Using ExecutorService.invokeAll, you do not have this power; you either block until are all completed, or you specify a timeout after which the incomplete are cancelled.

static class SleepingCallable implements Callable<String> {

  final String name;
  final long period;

  SleepingCallable(final String name, final long period) {
    this.name = name;
    this.period = period;
  }

  public String call() {
    try {
      Thread.sleep(period);
    } catch (InterruptedException ex) { }
    return name;
  }
}

现在,下面我将演示 invokeAll 是如何工作的:

Now, below I will demonstrate how invokeAll works:

final ExecutorService pool = Executors.newFixedThreadPool(2);
final List<? extends Callable<String>> callables = Arrays.asList(
    new SleepingCallable("quick", 500),
    new SleepingCallable("slow", 5000));
try {
  for (final Future<String> future : pool.invokeAll(callables)) {
    System.out.println(future.get());
  }
} catch (ExecutionException | InterruptedException ex) { }
pool.shutdown();

这会产生以下输出:

C:devscrap>java CompletionExample
... after 5 s ...
quick
slow

<小时>

使用 CompletionService,我们看到不同的输出:


Using CompletionService, we see a different output:

final ExecutorService pool = Executors.newFixedThreadPool(2);
final CompletionService<String> service = new ExecutorCompletionService<String>(pool);
final List<? extends Callable<String>> callables = Arrays.asList(
    new SleepingCallable("slow", 5000),
    new SleepingCallable("quick", 500));
for (final Callable<String> callable : callables) {
  service.submit(callable);
}
pool.shutdown();
try {
  while (!pool.isTerminated()) {
    final Future<String> future = service.take();
    System.out.println(future.get());
  }
} catch (ExecutionException | InterruptedException ex) { }

这会产生以下输出:

C:devscrap>java CompletionExample
... after 500 ms ...
quick
... after 5 s ...
slow

注意时间是相对于程序开始的,而不是之前的消息.

Note the times are relative to program start, not the previous message.

您可以在此处上找到完整代码.

You can find full code on both here.

这篇关于ExecutorCompletionService?如果我们有 invokeAll 为什么需要一个?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆