Яка різниця між 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, не існує конструктора без аргументів, і Future і FutureTask читаються лише зовні (встановлені методи FutureTask захищені). Значення буде встановлено в результаті обчислення зсередини.
З іншого боку, результат обіцянки може бути встановлений "ви" (або насправді ким-небудь) будь-коли, оскільки він має публічний метод встановлення. І CompletableFuture, і SettableFuture можна створити без будь-якого завдання, і їх значення можна встановити в будь-який час. Ви відправляєте обіцянку до клієнтського коду та виконуєте його пізніше, як хочете.
Зауважте, що CompletableFuture не є "чистою" обіцянкою, її можна ініціалізувати із завданням так само, як FutureTask, а його найкориснішою особливістю є непов'язане ланцюжок кроків обробки.
Також зауважте, що обіцянка не повинна бути підтипом майбутнього, і вона не повинна бути тим самим об’єктом. В Scala a Future об’єкт створюється асинхронним обчисленням або іншим об'єктом Promise. У C ++ ситуація схожа: об'єкт обіцянки використовується виробником, а майбутній об’єкт споживачем. Перевага цього розділення полягає в тому, що клієнт не може встановити значення майбутнього.
І Spring, і EJB 3.1 мають клас AsyncResult, схожий на обіцянки Scala / C ++. AsyncResult реалізує майбутнє, але це не справжнє майбутнє: асинхронні методи у Spring / EJB повертають інший об'єкт майбутнього, доступний лише для читання, завдяки деякій фоновій магії, і це друге "реальне" майбутнє може бути використане клієнтом для отримання результату.
Я усвідомлюю, що відповідь вже прийнята, але хотів би додати свої два центи:
TLDR: Майбутнє та Обіцяння - це дві сторони асинхронної операції: споживач / абонент та виробник / виконавець .
Як викликає асинхронного метод API, ви отримаєте в Futureякості ручки для результату обчислення в. Наприклад, ви можете зателефонувати get()на нього, щоб дочекатися завершення обчислення та отримання результату.
Тепер подумайте, як реально реалізується цей метод API: Реалізатор повинен Futureнегайно повернутися . Вони несуть відповідальність за завершення цього майбутнього, як тільки буде проведено обчислення (про що вони будуть знати, оскільки він реалізує логіку відправлення ;-)). Вони використовуватимуть a Promise/ CompletableFutureto робити саме так: Побудуйте та поверніть 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 просто видаляє котельну панель .... тоді (функція (результат) {.... з неї).
І насправді їх абстрагування досить добре, як конструктор обіцянок
new Promise( function(resolve, reject) { /* do it */ } );
дозволяє надати два зворотні виклики, які можна використати для Promiseуспішного або помилкового завершення. Так що лише код, який будує, Promiseможе завершити його, і код, який отримує вже сконструйований Promiseоб'єкт, має вигляд лише для читання.
З успадкуванням вищезазначеного можна досягти, якщо способи вирішення та відхилення є захищеними методами.
CompletableFutureможе мати деяку схожість з Promiseале, але це все ще не єPromise , тому що спосіб його споживання інший: Promiseрезультат вживається за допомогою виклику then(function), а функція виконується в контексті виробника відразу після виклику виробника resolve. FutureРезультат «s споживається викликом , getякий викликає споживчу нитка чекати , поки виробник потік не генерується значення, а потім обробляє його в споживача. Futureза своєю суттю багатопоточне, але ...
Promiseлише один потік (а насправді це саме те середовище, для якого вони були спочатку розроблені: програми javascript зазвичай мають лише один потік, тому ви не можетеFuture там їх реалізувати ). PromiseТому набагато легше і ефективніше Future, але Futureможе бути корисним у складних ситуаціях та потребує співпраці між потоками, які неможливо легко впорядкувати за допомогою Promises. Підводячи підсумок: Promiseце Futureпоштова модель, а модель - тяга (пор. Iterable vs Observable)
XMLHttpRequest). Я не вірю в твердження про ефективність, чи трапляються у вас якісь цифри? +++ Це сказало, дуже приємне пояснення.
getневирішених Futureобов'язково будуть входити 2 потокові контекстні комутатори, що, принаймні, через кілька років тому, ймовірно, вимагатиме близько 50 нас .
Щодо коду клієнта, Promise - це спостереження або додавання зворотного дзвінка, коли результат доступний, тоді як майбутнє - це чекати результату, а потім продовжувати. Теоретично все, що можна зробити з ф'ючерсами, що можна зробити з обіцянками, але через різницю стилів, отриманий API для обіцянок на різних мовах робить ланцюжок простішим.
У інтерфейсі майбутнього немає встановленого методу, отримуйте лише метод, тому він доступний лише для читання. Про CompletableFuture, ця стаття може бути корисною. повноцінне майбутнє
Promiseі ви дотримуєтесь його. Коли хтось дасть вам обіцянку, ви повинні дочекатися, щоб побачити, чи будуть вони її шануватиFuture