В чем разница между будущим и обещанием?

В чем разница между Future и Promise?
Они оба действуют как заполнитель для будущих результатов, но в чем основное различие?


person Evgenij Reznik    schedule 26.01.2013    source источник
comment
Вы можете сделать Promise, и вам решать, как его оставить. Когда кто-то другой дает вам обещание, вы должны подождать, чтобы увидеть, выполнят ли они его в Future   -  person Kevin Wright    schedule 03.02.2014
comment
wikipedia Будущее и обещания   -  person wener    schedule 13.01.2015
comment
Одна из наименее полезных статей в Википедии, которые я когда-либо читал   -  person Fulluphigh    schedule 20.11.2015
comment
dist-prog-book.com/chapter/2/futures.html   -  person Jim Hewitt    schedule 06.01.2018


Ответы (9)


Согласно этому обсуждению, 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);
person assylias    schedule 26.01.2013
comment
Это не ваша вина, Ассилиас, но этот отрывок из javadoc нуждается в серьезном ремонте со стороны достойного технического автора. На пятом прочтении я могу просто начать ценить то, что он пытается сказать ... и я подхожу к этому с пониманием будущего и уже имеющихся обещаний! - person Beetroot-Beetroot; 28.01.2013
comment
@ Beetroot-Beetroot похоже, что уже произошло. - person herman; 03.06.2015
comment
@herman Спасибо - я обновил ссылку, чтобы указать на окончательную версию javadoc. - person assylias; 03.06.2015
comment
@ Beetroot-Beetroot Вы должны проверить документацию для метода Exceptionally. Это было бы прекрасное стихотворение, но это исключительный недостаток читаемой документации. - person Fulluphigh; 20.11.2015
comment
@Fulluphigh Эта документация действительно забавна. - person JayArby; 06.06.2016
comment
Всем, кому интересно, @Fulluphigh имеет в виду this. Похоже, он был удален / переделан в Java 8. - person Cedric Reichenbach; 04.01.2017
comment
Ссылка @CedricReichenbach не работает - person Sniper; 25.05.2020

(Я пока не совсем доволен ответами, так что вот моя попытка ...)

Я думаю, что комментарий Кевина Райта («Вы можете дать обещание, и вы должны его сдержать. Когда кто-то другой дает вам обещание, вы должны подождать, чтобы увидеть, выполнят ли они его в будущем») резюмирует это довольно хорошо, но некоторые пояснения могут быть полезны.

Futures и promises - очень похожие концепции, разница в том, что будущее - это контейнер только для чтения для результата, который не пока существует, в то время как обещание может быть написано (обычно только один раз). CompletableFuture и Guava SettableFuture можно рассматривать как обещания, поскольку их ценность могут быть установлены («завершены»), но они также реализуют интерфейс Future, поэтому нет никакой разницы для клиента.

Результат будущего будет задан «кем-то другим» - результатом асинхронного вычисления. Обратите внимание, как FutureTask - классическое будущее - обязательно инициализировать с помощью Callable или Runnable, конструктора без аргументов нет, и Future, и FutureTask доступны только для чтения извне (установленные методы FutureTask защищены). Значение будет установлено на результат вычисления изнутри.

С другой стороны, результат обещания может быть установлен «вами» (или фактически кем угодно) в любое время, потому что он имеет общедоступный метод установки. И CompletableFuture, и SettableFuture можно создать без каких-либо задач, и их значение можно установить в любое время. Вы отправляете обещание клиентскому коду и выполняете его позже, когда захотите.

Обратите внимание, что CompletableFuture не является «чистым» обещанием, его можно инициализировать с помощью такой же задачи, как FutureTask, и его наиболее полезная функция - это несвязанная цепочка этапов обработки.

Также обратите внимание, что обещание не обязательно должно быть подтипом будущего и не обязательно должно быть тем же объектом. В Scala объект Future создается асинхронным вычислением или другим объектом Promise. В C ++ ситуация аналогична: объект обещания используется производителем, а объект будущего - потребителем. Преимущество такого разделения состоит в том, что клиент не может определять ценность будущего.

И Spring, и EJB 3.1 имеет класс AsyncResult, который похож на Scala / C ++. обещания. AsyncResult действительно реализует Future, но это не настоящее будущее: асинхронные методы в Spring / EJB возвращают другой объект Future только для чтения с помощью некоторой фоновой магии, и это второе «настоящее» будущее может использоваться клиентом для доступа к результату.

person lbalazscs    schedule 02.03.2015
comment
Я пытаюсь вспомнить разницу, как два конца трубы или мертвый почтовый ящик. Promise позволяет предоставлять данные, Future позволяет их извлекать. Я полагаю, что обещание - это тоже будущее - это удобство. - person Harald; 06.08.2020

Я знаю, что уже есть принятый ответ, но тем не менее хотел бы добавить свои два цента:

TL; DR: Future и Promise - это две стороны асинхронной операции: потребитель / вызывающая сторона и производитель / исполнитель.

Как вызывающий метод асинхронного API, вы получите Future как дескриптор результата вычисления. Вы можете, например, вызовите get() на нем, чтобы дождаться завершения вычисления и получить результат.

Теперь подумайте, как на самом деле реализован этот метод API: разработчик должен немедленно вернуть Future. Они несут ответственность за завершение этого будущего, как только будет выполнено вычисление (что они будут знать, потому что оно реализует логику отправки ;-)). Они будут использовать Promise / CompletableFuture для этого: создать и немедленно вернуть CompletableFuture и вызвать complete(T result) после завершения вычисления.

person Rahel Lüthy    schedule 06.01.2015
comment
Означает ли это, что Promise всегда является подклассом Future и что возможность записи Future просто скрывается за типом? - person devios1; 04.02.2018
comment
Я не думаю, что это подразумевается. С точки зрения реализации, это часто будет иметь место (например, в Java, Scala). - person Rahel Lüthy; 05.02.2018

Я приведу пример того, что такое 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) и отца нет дома, а только мама с ее «медленным кошельком», то ее обещание будет выполнено только в том случае, если программа живет дольше, чем нужно маме, чтобы получить деньги от кошелек.

Исполнитель по умолчанию действует как «демон» и не ждет, пока все обещания будут выполнены. Я не нашел хорошего описания этого факта ...

person Vladimir Nabokov    schedule 01.02.2017
comment
Это так весело читать! Не думаю, что смогу забыть будущее и обещать больше. - person user1532146; 09.12.2017
comment
Это нужно принять как ответ. Это все равно что читать рассказ. Спасибо @Vladimir - person Phillen; 11.02.2019
comment
Спасибо @Vladimir - person intvprep; 03.03.2020

Не уверен, что это может быть ответ, но, поскольку я вижу, что другие сказали для кого-то, может показаться, что вам нужны две отдельные абстракции для обеих этих концепций, чтобы одна из них (Future) была просто представлением другой только для чтения. (Promise) ... но на самом деле это не нужно.

Например, посмотрите, как обещания определены в javascript:

https://promisesaplus.com/

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 просто удаляет шаблон .... then (function (result) {.... от этого).

И на самом деле их абстракция хороша как конструктор обещаний.

new Promise( function(resolve, reject) { /* do it */ } );

позволяет предоставить два обратных вызова, которые можно использовать для успешного завершения Promise или с ошибкой. Так что только код, конструирующий Promise, может его завершить, а код, который получает уже построенный объект Promise, имеет доступ только для чтения.

С помощью наследования вышеуказанное может быть достигнуто, если resolve и reject являются защищенными методами.

person bodrin    schedule 27.05.2016
comment
+1. Это правильный ответ на этот вопрос. CompletableFuture может иметь некоторое сходство с Promise, но это все равно не Promise, потому что способ его использования отличается: результат Promise потребляется вызовом then(function), а функция выполняется < i> в контексте производителя сразу после того, как производитель вызывает resolve. Результат Future потребляется вызовом get, который заставляет поток-получатель ждать, пока поток-производитель не сгенерирует значение, а затем обрабатывает его в потребителе. Future по своей природе многопоточен, но ... - person Periata Breatta; 03.11.2016
comment
... вполне возможно использовать Promise только с одним потоком (и на самом деле это именно та среда, для которой они изначально были разработаны: приложения javascript обычно имеют только один поток, поэтому вы не можете реализовать там Future). Promise поэтому намного легче и эффективнее, чем Future, но Future может быть полезен в более сложных ситуациях, требующих взаимодействия между потоками, которые не могут быть легко организованы с помощью Promises. Подводя итог: Promise - это модель выталкивания, а Future - модель вытягивания (см. Iterable vs Observable) - person Periata Breatta; 03.11.2016
comment
@PeriataBreatta Даже в однопоточной среде должно быть что-то, выполняющее обещание (которое обычно работает как другой поток, например, XMLHttpRequest). Я не верю утверждениям об эффективности, у вас есть какие-то цифры? +++ Тем не менее, очень хорошее объяснение. - person maaartinus; 07.11.2016
comment
@maaartinus - да, что-то должно выполнить обещание, но это может (и фактически во многих случаях) сделать это с помощью цикла верхнего уровня, который опрашивает изменения во внешнем состоянии и разрешает любые обещания, относящиеся к завершенным действиям. Что касается эффективности, у меня нет точных цифр конкретно для Promises, но обратите внимание, что вызов get на неразрешенном Future обязательно будет включать 2 переключения контекста потока, что, по крайней мере, несколько лет назад, вероятно, потребовало около 50 мкс. - person Periata Breatta; 11.11.2016
comment
@PeriataBreatta На самом деле ваш комментарий должен быть принятым решением. Я искал объяснение (вытягивание / выталкивание, однопоточное / многопоточное), подобное вашему. - person Thomas Jacob; 06.05.2019

Для клиентского кода Promise предназначен для наблюдения или присоединения обратного вызова, когда доступен результат, тогда как Future ожидает результата, а затем продолжает. Теоретически все, что можно сделать с фьючерсами, можно сделать и с обещаниями, но из-за разницы в стилях результирующий API для обещаний на разных языках упрощает создание цепочек.

person user2562234    schedule 25.11.2017

В интерфейсе Future нет метода set, только метод get, поэтому он доступен только для чтения. О CompletableFuture эта статья может оказаться полезной. completetablefuture

person Jacky    schedule 06.09.2017

В этом примере вы можете посмотреть, как Promises можно использовать в Java для создания асинхронных последовательностей вызовов:

doSomeProcess()
    .whenResult(result -> System.out.println(String.format("Result of some process is '%s'", result)))
    .whenException(e -> System.out.println(String.format("Exception after some process is '%s'", e.getMessage())))
    .map(String::toLowerCase)
    .mapEx((result, e) -> e == null ? String.format("The mapped result is '%s'", result) : e.getMessage())
    .whenResult(s -> System.out.println(s));
person George Meyer    schedule 02.07.2020

Future и Promise - прокси-объект для неизвестного результата

Promise завершает Future

  • Promise - запись / производитель неизвестного результата.
  • Future - чтение / получатель неизвестного результата. Имеет следующие состояния: ожидает, выполнено, отменено.
//Future has a reference to Promise
Future -> Promise

Как producer я promise кое-что и отвечаю за это

Как consumer, получивший promise, я ожидаю, что результат будет future. В future я могу использовать promise или отклонить его

Что касается Java CompletableFutures, это Promise, потому что вы можете установить результат, а также реализует Future

person yoAlex5    schedule 06.02.2021