是使用invokeAll还是submit——java Executor服务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34440604/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 22:54:41  来源:igfitidea点击:

Whether to use invokeAll or submit - java Executor service

javaconcurrencyexecutorservicejava.util.concurrent

提问by Ankit

I have a scenario where I have to execute 5 thread asynchronously for the same callable. As far as I understand, there are two options:

我有一个场景,我必须为同一个可调用对象异步执行 5 个线程。据我了解,有两种选择:

1) using submit(Callable)

1) 使用提交(Callable)

ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = new ArrayList<>();
for(Callable callableItem: myCallableList){
    futures.add(executorService.submit(callableItem));
}

2) using invokeAll(Collections of Callable)

2) 使用 invokeAll(Collections of Callable)

ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = executorService.invokeAll(myCallableList));
  1. What should be the preferred way?
  2. Is there any disadvantage or performance impact in any of them compared to the other one?
  1. 什么应该是首选方式?
  2. 与另一个相比,它们中的任何一个是否有任何缺点或性能影响?

回答by Ravindra babu

Option 1: You are submitting the tasks to ExecutorServiceand you are not waiting for the completion of all tasks, which have been submitted to ExecutorService

选项 1:您正在提交任务,ExecutorService而不是等待所有已提交的任务完成ExecutorService

Option 2: You are waiting for completion of all tasks, which have been submitted to ExecutorService.

选项 2:您正在等待完成所有已提交给ExecutorService.

What should be the preferred way?

什么应该是首选方式?

Depending on application requirement, either of them is preferred.

根据应用要求,它们中的任何一个都是首选。

  1. If you don't want to wait after task submit() to ExecutorService, prefer Option 1.
  2. If you need to wait for completion of all tasks, which have been submitted to ExecutorService, prefer Option 2.
  1. 如果您不想在任务 submit() 之后等待ExecutorService,则更喜欢Option 1.
  2. 如果您需要等待已提交到的所有任务完成ExecutorService,则首选Option 2.

Is there any disadvantage or performance impact in any of them compared to the other one?

与另一个相比,它们中的任何一个是否有任何缺点或性能影响?

If your application demands Option 2, you have to wait for completion of all tasks submitted to ExecutorServiceunlike in Option 1. Performance is not criteria for comparison as both are designed for two different purposes.

如果您的应用程序需要选项 2,则ExecutorService与选项 1 不同,您必须等待所有提交的任务完成。性能不是比较标准,因为两者都是为两个不同目的而设计的。

And one more important thing: Whatever option you prefer, FutureTaskswallows Exceptions during task execution. You have to be careful. Have a look at this SE question: Handling Exceptions for ThreadPoolExecutor

还有一件更重要的事情:无论您喜欢哪种选择,都会FutureTask在任务执行期间吞下 Exceptions。你必须要小心。看看这个 SE 问题:Handling Exceptions for ThreadPoolExecutor

With Java 8, you have one more option: ExecutorCompletionService

使用 Java 8,您还有一个选择:ExecutorCompletionService

A CompletionServicethat uses a supplied Executor to execute tasks. This class arranges that submitted tasks are, upon completion, placed on a queue accessible using take. The class is lightweight enough to be suitable for transient use when processing groups of tasks.

一个CompletionService使用所提供的Executor来执行任务。此类安排提交的任务在完成后放置在使用 take 可访问的队列中。该类足够轻量级,适合在处理任务组时临时使用。

Have a look at related SE question: ExecutorCompletionService? Why do need one if we have invokeAll?

看看相关的 SE 问题:ExecutorCompletionService? 如果我们有 invokeAll 为什么需要一个?

回答by Fred Porciúncula

EDIT:

编辑:

There is actually a difference between them. For some reason, invokeAll()will call get()for each futureproduced. Thus, it will wait the tasks to finish and that is why it may throw InterruptedException(while submit()throws nothing).

他们之间其实是有区别的。出于某种原因,invokeAll()会要求get()每个future产生。因此,它将等待任务完成,这就是它可能抛出InterruptedException(而submit()什么都不抛出)的原因。

That's the Javadoc for the invokeAll()method:

这是该invokeAll()方法的 Javadoc :

Executes the given tasks, returning a list of Futures holding their status and results when all complete.

执行给定的任务,返回一个 Futures 列表,在所有完成时保存它们的状态和结果。

So, both strategies basically do the same, but if you call invokeAll()you'll be blocked until all tasks are done.

所以,这两种策略基本上都是一样的,但是如果你打电话,invokeAll()你会被阻塞,直到所有任务都完成。



Original (incomplete) answer:

原始(不完整)答案:

The invokeAll()method is there exactly for situations like these. You should definitely use it.

invokeAll()方法完全适用于此类情况。你绝对应该使用它。

You don't really need to instantiate that List, though:

不过,您实际上并不需要实例化它List

ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = executorService.invokeAll(myCallableList));

This should be enough, and it looks way cleaner than the first alternative.

这应该足够了,它看起来比第一种选择更干净。

回答by parampreet bawa

Suppose you have a task whose result depends on number of independentaly executable tasks. But for initial task to complete you only have limited time. Like its an API call.

假设您有一个任务,其结果取决于独立可执行任务的数量。但是要完成初始任务,您只有有限的时间。就像它的 API 调用一样。

So for example you have 100ms for top level task to complete and there are 10 dependant tasks as well. For that if you are using a submit here how the code will look like.

例如,您有 100 毫秒的时间来完成顶级任务,并且还有 10 个相关任务。为此,如果您在此处使用提交,代码将是什么样子。

List<Callable> tasks = []// assume contains sub tasks
List<Future> futures = [] 
for(Callable task: tasks) {
   futures.add(service.submit(task));
}

for(Future futute: futures) {
    future.get(100, TimeUnit.MILLISECONDS);
}

So if each of sub tasks took exaclty 50ms to complete the above piece of code would take 50 ms. But if each of sub tasks took 1000 ms to complete the above would take 100 * 10 = 1000 ms or 1s. This is making difficult to compute the total time to be less than 100ms for all subtasks.

因此,如果每个子任务花费 50 毫秒来完成上述代码段将花费 50 毫秒。但是如果每个子任务需要 1000 ms 来完成上面的将需要 100 * 10 = 1000 ms 或 1s。这使得计算所有子任务的总时间小于 100 毫秒变得困难。

invokeAll method helps us in such scenario

invokeAll 方法在这种情况下可以帮助我们

List<Futures> futures = service.invokeall(tasks, 100, TimeUnit.MILLISECONDS)
for(Future future: futures) {
   if(!future.isCancelled()) {
       results.add(future.get());
   }
}

This way the maximum time it would take is inly 100 ms even if individual of subtasks took more than that.

这样,即使单个子任务花费的时间更长,它所花费的最长时间也仅为 100 毫秒。