Чим відрізняються ф’ючерси та обіцянки Clojure?


86

І ф'ючерси, і обіцянки блокуються, поки вони не розрахують свої значення, то яка різниця між ними?


8
Я не впевнений, чому -1 на запитання, чи це питання, на які ви не знаєте відповіді, перш ніж задавати зараз погані речі?
ТІЛЬКИ МОЙ правильний ДУМКА

Я не відповів -1 жодної з відповідей ?? Як ми можемо визначити, хто поставив -1 на запитання чи відповідь?
appshare.co

Ми з вами не можемо, Зубайре. Мені просто цікаво, хто поставив -1 на ваше запитання, враховуючи, що це цілком розумне запитання, і це, безумовно, тема для SO.
ТІЛЬКИ МОЙ правильний ДУМКА

Відповіді:


54

Відповідаючи словами Clojure, ось кілька прикладів з екранізації Шона Девліна :

(def a-promise (promise))
(deliver a-promise :fred)

(def f (future (some-sexp)))
(deref f)

Зверніть увагу, що в обіцянці ви явно передаєте значення, яке ви вибрали в подальшому обчисленні ( :fredу цьому випадку). Навпаки, майбутнє споживається там, де воно було створене. some-exprІмовірно запущений за лаштунками , і розраховується в тандемі ( в кінці кінців), але якщо він залишається невичісленним на той час вона доступна потік блокується до тих пір, поки не доступно.


відредаговано додати

Для подальшого розрізнення обіцянки від майбутнього зверніть увагу на таке:

обіцянка

  1. Ви створюєте promise. Цей об’єкт обіцянки тепер можна передати будь-якому потоку.
  2. Ви продовжуєте з розрахунками. Це можуть бути дуже складні розрахунки, що включають побічні ефекти, завантаження даних, введення користувачами, доступ до бази даних, інші обіцянки - що завгодно. Код буде дуже схожий на ваш основний код в будь-якій програмі.
  3. Коли ви закінчите, ви зможете deliverотримати результати для цього обіцяного об'єкта.
  4. Будь-який предмет, який намагається виконати derefвашу обіцянку, перш ніж ви закінчите з розрахунком, буде блокуватися, поки ви не закінчите. Після того, як ви закінчите і виконаєте deliverобіцянку, обіцянка більше не блокуватиметься.

майбутнє

  1. Ви створюєте своє майбутнє. Частина вашого майбутнього - це вираз для розрахунку.
  2. Майбутнє може виконуватися одночасно або не виконуватися. Йому може бути призначений потік, можливо, з пулу. Це могло просто чекати і нічого не робити. З вашої точки зору ви не можете сказати .
  3. У якийсь момент у вас (або іншої нитки) derefмайбутнє. Якщо обчислення вже завершено, ви отримуєте його результати. Якщо це ще не завершено, ви блокуєте, поки воно не завершиться. (Імовірно, якщо він ще не розпочався, derefце означає, що він починає виконуватися, але це теж не гарантується.)

Хоча ви можете зробити вираз у майбутньому таким же складним, як і код, що слідує за створенням обіцянки, сумнівно, що це бажано. Це означає, що ф’ючерси дійсно більше підходять для швидких фонових розрахунків, тоді як обіцянки дійсно більше підходять для великих, складних шляхів виконання. З точки зору доступних розрахунків, обіцянки здаються трохи більш гнучкими та орієнтованими на те, що творець обіцянок виконує роботу, і ще на одну нитку, яка збирає урожай. Ф'ючерси більше орієнтовані на автоматичний запуск потоку (без потворних та схильних до помилок накладних витрат) і продовження інших справ, поки вам - вихідному потоку - не знадобляться результати.


Але ви можете мати будь-який блок калькуляції, поки не закінчиться ні обіцянка, ні майбутнє. тобто: (@a + @b) працюватиме однаково як з майбутнім, так і з обіцянкою
appshare.co

2
Обіцянка забезпечує більшу гнучкість, як мені здається. Я створюю обіцянку. Я передаю цю обіцянку іншій темі. Потім я можу зробити багато складних розрахунків, включаючи очікування вводу-виводу, завантаження даних з Інтернету, очікування введення користувачем тощо. Коли все це зроблено, я передаю обіцянку з отриманим значенням. Майбутнє охоплює один S-вираз. Напевно, це може бути дуже, дуже складний S-вираз, але там він був би трохи ... жорстким. Крім того, майбутнє виконує свою роботу автоматично в потоці (або пулі). Зробити те саме в обіцянці означало б ще більше роботи.
ТІЛЬКИ МОЙ правильний ДУМКА

FWIW, оскільки один s-вираз може бути викликом довільного шляху коду, справа не в тому, скільки коду ви можете втиснути у вираз. Тому замість того, щоб говорити, що обіцянка є «більш гнучкою», я б сказав, що її мета просто інша. Інакше, навіщо обидва?
Джефф

2
Тільки для запису, futureосновна частина дзвінка може включати N sexprs.
vemv

Це пояснення повинно бути частиною Clojure Doc
Піюш Катарія

25

Майбутнє і Обіцянка є механізмами передачі результату асинхронних обчислень від виробника до споживача.

У разі майбутнього обчислення визначаються в момент створення майбутнього і асинхронне виконання починається «якомога швидше». Він також "знає", як створити асинхронне обчислення.

У разі обчислення Promise час його початку та [можливий] асинхронний виклик відокремлюються від механізму доставки. Коли доступний результат обчислення , Виробник повинен зателефонувати явно, що також означає, що Виробник контролює, коли результат стане доступним. deliver

Для Promises Clojure допускає помилку в дизайні, використовуючи один і той же об'єкт (результат promiseвиклику) як для виробництва ( deliver), так і для споживання ( deref) результату обчислення . Це дві дуже різні можливості, і їх слід розглядати як такі.


@oskarkv Припустимо, ви створили обіцянку і дали її 3 клієнтам. Ніщо не заважає одному з клієнтів вирішити це з помилковим результатом і подати сигнал двом іншим клієнтам. Крім того, ви більше не зможете вирішити цю обіцянку. На відміну від цього, якщо у вас була пара обіцянок + розв'язувач, дала обіцянку своїм клієнтам і зберегла роздільник для себе, цей сценарій стає неможливим. Для отримання додаткової інформації запропоновані пошукові терміни - "контроль доступу на основі можливостей" та "безпека на основі можливостей".
Дімагог,

1
Я не впевнений, чи promiseбуде зручним поєднання захисту з таким простим посилальним типом (перевірте його impl) . «Злі» споживачі трапляються рідко; ніщо не заважає вам побудувати власну абстракцію на додаток до обіцянок.
vemv

8
Справа не в безпеці, але так трапляється, що програмування на основі можливостей часто описується стосовно безпеки. Тут все стосується правильності коду. Часто використовується термін "правильний за побудовою", а питання "чи можете ви побудувати неправильну програму"? Не навмисно, а випадково. З одним об’єктом Promise ви можете, а з двома окремими об’єктами - не.
Dimagog

Вам ніщо не заважає повернути обіцянку, яку неможливо виконати, якщо це те, що ви хочете: (defn undeliverable-promise [] (let [p (promise)] (reify clojure.lang.IDeref (deref [_] (deref p)) clojure.lang.IBlockingDeref (deref [_ ms val] (deref p ms val)) clojure.lang.IPending (isRealized [_] (.isRealized p)) clojure.lang.IFn (invoke [_ _] nil))))
tapichu

Вказуючи на різницю між нерозв’язаністю механізму обчислень, це повідомлення стало дійсно стислим поясненням. Дякую!
синтомат

3

Уже є відмінні відповіді, тому лише додавши резюме "як використовувати":

І те, і інше

Створення обіцянки або майбутнього негайно повертає посилання. Це посилання блокується на @ / deref, поки результат обчислення не буде наданий іншим потоком.

Майбутнє

Створюючи майбутнє, ви забезпечуєте синхронну роботу, яку потрібно виконати. Він виконується в потоці з виділеного необмеженого пулу.

Пообіцяй

Ви не наводите аргументів під час створення обіцянки. Посилання слід передати іншому потоку користувача, який буде deliverрезультатом.


1

У Clojure, promise, futureі delayцю обіцянку, як об'єкти. Всі вони представляють обчислення, на які клієнти можуть чекати, використовуючи deref(або @). Клієнти повторно використовують результат, так що обчислення не запускаються кілька разів.

Вони відрізняються способом виконання обчислень:

  • futureрозпочне обчислення в іншому робочому потоці. derefбуде блокувати, поки результат не буде готовий.

  • delayбуде виконувати обчислення ліниво, коли перший клієнт використовує deref, або force.

  • promiseпропонує найбільшу гнучкість, оскільки його результат доставляється будь-яким спеціальним способом за допомогою deliver. Ви можете використовувати його , коли ні futureабо delayвідповідати вашому випадку використання.


-4

По-перше, a Promiseє a Future. Я думаю, ви хочете знати різницю між a Promiseта a FutureTask.

A Futureявляє собою значення, яке наразі не відоме, але буде відоме в майбутньому.

A FutureTaskпредставляє результат обчислення, яке відбудеться в майбутньому (можливо, в якомусь пулі потоків). При спробі отримати доступ до результату, якщо обчислення ще не відбулося, воно блокується. В іншому випадку результат негайно повертається. Жодна інша сторона не бере участь у обчисленні результату, оскільки обчислення вказані вами заздалегідь.

A Promiseявляє собою результат, який обіцянок передасть обіцяному в майбутньому. У цьому випадку ви обіцяєте, а обіцянок - той, хто дав вам Promiseпредмет. Подібно до FutureTask, якщо ви намагаєтесь отримати доступ до результату до того, Promiseяк було виконано, він блокується, поки обіцянка не виконає Promise. Після того, як Promiseце виконано, ви отримуєте одне і те ж значення завжди і негайно. На відміну від FutureTask, тут задіяна інша сторона, яка зробила Promise. Що інша сторона відповідає за обчислення та виконання Promise.

У цьому сенсі a FutureTask- це Promiseви, яке ви зробили для себе.


Ви впевнені, що обіцянка - це майбутнє? я не можу виявити, що він реалізує інтерфейс. github.com/richhickey/clojure/blob/…
Мікаель Сундберг

вибачте, я пропустив enter. Моє запитання змінено
Mikael Sundberg

Моя відповідь у загальному сенсі, а не в конкретному Clojure.
Абхінав Саркар

9
Відповісти на питання про Clojure за допомогою Java-коду здається дещо химерним.
ТІЛЬКИ МОЙ правильний ДУМКА
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.