Какая разница между 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может быть полезен в ситуациях, которые являются более сложными и требуют взаимодействия между потоками, которые не могут быть легко организованы с помощью Promises. Подводя итог: Promiseэто модель push, в то время Futureкак модель pull (ср. Iterable против Observable)
XMLHttpRequest). Я не верю утверждению эффективности, у вас есть какие-то цифры? +++ При этом очень хорошее объяснение.
getнеразрешенного решения Futureобязательно потребует двухпоточных переключений контекста, что, по крайней мере, несколько лет назад могло потребовать около 50 человек .
Для клиентского кода Promise предназначен для наблюдения или присоединения обратного вызова, когда результат доступен, тогда как Future должен ждать результата и затем продолжать. Теоретически все, что можно сделать с фьючерсами, что можно сделать с обещаниями, но из-за разницы в стиле, результирующий API для обещаний на разных языках облегчает цепочку.
Не задан метод в интерфейсе Future, только метод get, поэтому он доступен только для чтения. О CompletableFuture эта статья может быть полезной. completablefuture
Promiseи это зависит от вас, чтобы сохранить его. Когда кто-то еще дает вам обещание, вы должны подождать, чтобы увидеть, соблюдают ли они его вFuture