ExecutorService.submit(Task) vs CompletableFuture.supplyAsync(Task, Executor)
Чтобы запускать некоторые вещи параллельно или асинхронно, я могу использовать либо ExecutorService: <T> Future<T> submit(Runnable task, T result);
, либо CompletableFuture Api: static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);
(Предположим, что я использую в обоих случаях тот же Исполнитель)
Помимо возвращаемого типа Future vs. CompletableFuture есть ли какие-либо примечательные отличия. Или Когда использовать что?
И каковы различия, если я использую CompletableFutureApi со стандартным Executor (метод без исполнителя)?
Ответы
Ответ 1
Помимо возвращаемого типа Future vs. CompletableFuture есть ли какие-либо примечательные отличия. Или Когда использовать что?
Это довольно просто. Вы используете Future
, когда хотите, чтобы исполняемый поток ожидал ответа на вычисление async. Примером этого является параллельное слияние/сортировка. Сортировка слева асинхронно, сортировка справа синхронно, ждать слева для завершения (future.get()
), слить результаты.
Вы используете CompleteableFuture
, когда хотите выполнить какое-либо действие с результатом после завершения, асинхронно из исполняемого потока. Например: я хочу сделать некоторые вычисления асинхронно, и когда я вычислил, напишите результаты в какую-то систему. Запрашивающий поток, возможно, не нужно ждать результата.
Вы можете воспроизвести приведенный выше пример в одном исполняемом файле Future, но CompletableFuture
предлагает более свободный интерфейс с улучшенной обработкой ошибок.
Это действительно зависит от того, что вы хотите сделать.
И каковы различия, если я использую CompletableFutureApi со стандартным Executor (метод без исполнителя)?
Он будет делегировать ForkJoin.commonPool()
, который является размером по умолчанию для количества процессоров в вашей системе. Если вы делаете что-то интенсивное вложение (чтение и запись в файловую систему), вы должны определить пул потоков по-разному.
Если процессор интенсивный, использование commonPool имеет наибольший смысл.
Ответ 2
CompletableFuture имеет богатые функции, такие как объединение нескольких фьючерсов, объединение фьючерсов, выполнение некоторых действий после будущего исполнения (как синхронно, так и асинхронно) и т.д.
Однако, CompletableFuture не отличается от Future в плане производительности. Даже при объединении нескольких экземпляров CompletableFuture (с использованием .thenCombine и .join в конце) ни один из них не выполняется, если мы не вызываем метод .get, и в течение этого времени вызывающий поток блокируется. Я чувствую себя с точки зрения производительности, это не лучше, чем будущее.
Пожалуйста, дайте мне знать, если мне не хватает какого-либо аспекта работы здесь.
Ответ 3
Это прояснило для меня разницу между будущим в готовом будущем немного больше: Разница между будущим и обещанием
CompletableFuture больше похоже на обещание.