Какая разница между Future
а Promise
?
Они оба действуют как заполнитель для будущих результатов, но где главное отличие?
Какая разница между Future
а Promise
?
Они оба действуют как заполнитель для будущих результатов, но где главное отличие?
Ответы:
Согласно этому обсуждению , Promise
наконец-то был вызван CompletableFuture
для включения в Java 8, и его Javadoc объясняет:
Будущее, которое может быть явно завершено (с указанием его значения и статуса) и может использоваться в качестве CompletionStage, поддерживающего зависимые функции и действия, которые инициируются после его завершения.
Пример также приведен в списке:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Обратите внимание, что финальный API немного отличается, но допускает аналогичное асинхронное выполнение:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
(Пока я не совсем доволен ответами, так что моя попытка ...)
Я думаю, что комментарий Кевина Райта ( «Вы можете сделать Обещание, и вы должны его выполнить. Когда кто-то еще дает вам обещание, вы должны подождать, чтобы увидеть, выполнят ли они его в будущем» ), суммирует его довольно хорошо, но некоторые объяснение может быть полезным.
Фьючерсы и обещания - это довольно похожие понятия, разница в том, что будущее - это контейнер только для чтения для результата, которого еще нет, а обещание можно написать (обычно только один раз). Java 8 CompletableFuture и Guava SettableFuture можно рассматривать как обещания, поскольку их значение может быть установлено («завершено»), но они также реализуют интерфейс Future, поэтому для клиента нет никакой разницы.
Результат будущего будет установлен «кем-то другим» - результатом асинхронного вычисления. Обратите внимание, что FutureTask - классическое будущее - нужно инициализировать с помощью Callable или Runnable, конструктор без аргументов отсутствует, а FutureTask и FutureTask доступны только для чтения извне (методы набора FutureTask защищены). Значение будет установлено на результат вычисления изнутри.
С другой стороны, результат обещания может быть установлен «вами» (или фактически кем угодно) в любое время, потому что у него есть метод открытого сеттера. И CompletableFuture, и SettableFuture могут быть созданы без каких-либо задач, и их значение может быть установлено в любое время. Вы отправляете обещание клиентскому коду и выполняете его позже, как пожелаете.
Обратите внимание, что CompletableFuture не является «чистым» обещанием, его можно инициализировать с помощью задачи, аналогичной FutureTask, и его наиболее полезная функция - это не связанная цепочка этапов обработки.
Также обратите внимание, что обещание не обязательно должно быть подтипом будущего и не обязательно должно быть одним и тем же объектом. В Scala объект Future создается асинхронным вычислением или другим объектом Promise. В C ++ ситуация аналогична: объект обещания используется производителем, а объект будущего - потребителем. Преимущество такого разделения заключается в том, что клиент не может установить ценность будущего.
И Spring, и EJB 3.1 имеют класс AsyncResult, который похож на обещания Scala / C ++. AsyncResult реализует Future, но это не настоящее будущее: асинхронные методы в Spring / EJB возвращают другой объект Future, доступный только для чтения, посредством некоторой фоновой магии, и это второе «реальное» будущее может использоваться клиентом для доступа к результату.
Я знаю, что уже есть принятый ответ, но все же хотел бы добавить свои два цента:
TLDR: будущее и обещание - это две стороны асинхронной операции: потребитель / вызывающий абонент против производителя / разработчика .
Как вызывающий асинхронного метод API, вы получите в Future
качестве ручки для результата вычислению в. Например, вы можете вызвать get()
его, чтобы дождаться завершения вычислений и получить результат.
Теперь подумайте, как на самом деле реализован этот метод API: разработчик должен Future
немедленно вернуть a . Они несут ответственность за завершение этого будущего, как только вычисление будет выполнено (что они узнают, поскольку оно реализует логику диспетчеризации ;-)). Они будут использовать Promise
/, CompletableFuture
чтобы сделать именно это: сконструировать и вернуть CompletableFuture
сразу, и вызвать, как complete(T result)
только вычисление будет сделано.
Я приведу пример того, что такое Promise и как его значение может быть установлено в любое время, в отличие от Future, значение которого доступно только для чтения.
Предположим, у вас есть мама, и вы просите у нее денег.
// Now , you trick your mom into creating you a promise of eventual
// donation, she gives you that promise object, but she is not really
// in rush to fulfill it yet:
Supplier<Integer> momsPurse = ()-> {
try {
Thread.sleep(1000);//mom is busy
} catch (InterruptedException e) {
;
}
return 100;
};
ExecutorService ex = Executors.newFixedThreadPool(10);
CompletableFuture<Integer> promise =
CompletableFuture.supplyAsync(momsPurse, ex);
// You are happy, you run to thank you your mom:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));
// But your father interferes and generally aborts mom's plans and
// completes the promise (sets its value!) with far lesser contribution,
// as fathers do, very resolutely, while mom is slowly opening her purse
// (remember the Thread.sleep(...)) :
promise.complete(10);
Выход этого:
Thank you mom for $10
Мамины обещания были созданы, но ждали какого-то «завершения» мероприятия.
CompletableFuture<Integer> promise...
Вы создали такое событие, принимая ее обещание и объявляя о своих планах поблагодарить маму:
promise.thenAccept...
В этот момент мама начала открывать сумочку ... но очень медленно ...
и отец вмешался намного быстрее и выполнил обещание вместо твоей мамы
promise.complete(10);
Вы заметили исполнителя, который я написал явно?
Интересно, что если вместо этого вы используете неявного исполнителя по умолчанию (commonPool), а папа не дома, а только мама с ее «медленным кошельком», то ее обещание будет выполнено только в том случае, если программа живет дольше, чем мама должна получить деньги от кошелек.
Исполнитель по умолчанию действует как «демон» и не ожидает выполнения всех обещаний. Я не нашел хорошего описания этого факта ...
Не уверен, что это может быть ответом, но, как я вижу, что другие говорили о ком-то, может показаться, что вам нужны две отдельные абстракции для обеих этих концепций, так что одна из них ( Future
) является представлением только для чтения ( Promise
) ... но на самом деле это не нужно.
Например, посмотрите, как определяются обещания в javascript:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Основное внимание уделяется компоновке с использованием такого then
метода, как:
asyncOp1()
.then(function(op1Result){
// do something
return asyncOp2();
})
.then(function(op2Result){
// do something more
return asyncOp3();
})
.then(function(op3Result){
// do something even more
return syncOp4(op3Result);
})
...
.then(function(result){
console.log(result);
})
.catch(function(error){
console.log(error);
})
что делает асинхронные вычисления похожими на синхронные:
try {
op1Result = syncOp1();
// do something
op1Result = syncOp2();
// do something more
op3Result = syncOp3();
// do something even more
syncOp4(op3Result);
...
console.log(result);
} catch(error) {
console.log(error);
}
что довольно круто (Не так круто, как async-await, но async-await просто удаляет шаблон .... затем (function (result) {.... from it).
И на самом деле их абстракция довольно хороша как конструктор обещаний
new Promise( function(resolve, reject) { /* do it */ } );
позволяет вам предоставить два обратных вызова, которые можно использовать для Promise
успешного завершения или с ошибкой. Таким образом, только код, Promise
который создает Promise
объект, может завершить его, а код, который получает уже созданный объект, имеет представление только для чтения.
С наследованием вышеупомянутое может быть достигнуто, если решить и отклонить являются защищенными методами.
CompletableFuture
может иметь некоторое сходство с a, Promise
но это все же не такPromise
, потому что способ, которым он предназначен для использования, отличается: результат a Promise
потребляется при вызове then(function)
, а функция выполняется в контексте производителя сразу после вызова производителя resolve
, Future
Результат A потребляется вызовом, get
который заставляет поток потребителя ждать, пока поток производителя не сгенерирует значение, а затем обрабатывает его в потребителе. Future
по своей сути многопоточный, но ...
Promise
только с одним потоком (и фактически это именно та среда, для которой они были изначально разработаны: приложения javascript обычно имеют только один поток, поэтому вы не можете реализовать их Future
там). Promise
поэтому он намного легче и эффективнее Future
, но Future
может быть полезен в ситуациях, которые являются более сложными и требуют взаимодействия между потоками, которые не могут быть легко организованы с помощью Promise
s. Подводя итог: Promise
это модель push, в то время Future
как модель pull (ср. Iterable против Observable)
XMLHttpRequest
). Я не верю утверждению эффективности, у вас есть какие-то цифры? +++ При этом очень хорошее объяснение.
get
неразрешенного решения Future
обязательно потребует двухпоточных переключений контекста, что, по крайней мере, несколько лет назад могло потребовать около 50 человек .
Для клиентского кода Promise предназначен для наблюдения или присоединения обратного вызова, когда результат доступен, тогда как Future должен ждать результата и затем продолжать. Теоретически все, что можно сделать с фьючерсами, что можно сделать с обещаниями, но из-за разницы в стиле, результирующий API для обещаний на разных языках облегчает цепочку.
Не задан метод в интерфейсе Future, только метод get, поэтому он доступен только для чтения. О CompletableFuture эта статья может быть полезной. completablefuture
Promise
и это зависит от вас, чтобы сохранить его. Когда кто-то еще дает вам обещание, вы должны подождать, чтобы увидеть, соблюдают ли они его вFuture