І ф'ючерси, і обіцянки блокуються, поки вони не розрахують свої значення, то яка різниця між ними?
І ф'ючерси, і обіцянки блокуються, поки вони не розрахують свої значення, то яка різниця між ними?
Відповіді:
Відповідаючи словами Clojure, ось кілька прикладів з екранізації Шона Девліна :
(def a-promise (promise))
(deliver a-promise :fred)
(def f (future (some-sexp)))
(deref f)
Зверніть увагу, що в обіцянці ви явно передаєте значення, яке ви вибрали в подальшому обчисленні ( :fred
у цьому випадку). Навпаки, майбутнє споживається там, де воно було створене. some-expr
Імовірно запущений за лаштунками , і розраховується в тандемі ( в кінці кінців), але якщо він залишається невичісленним на той час вона доступна потік блокується до тих пір, поки не доступно.
відредаговано додати
Для подальшого розрізнення обіцянки від майбутнього зверніть увагу на таке:
promise
. Цей об’єкт обіцянки тепер можна передати будь-якому потоку.deliver
отримати результати для цього обіцяного об'єкта.deref
вашу обіцянку, перш ніж ви закінчите з розрахунком, буде блокуватися, поки ви не закінчите. Після того, як ви закінчите і виконаєте deliver
обіцянку, обіцянка більше не блокуватиметься.deref
майбутнє. Якщо обчислення вже завершено, ви отримуєте його результати. Якщо це ще не завершено, ви блокуєте, поки воно не завершиться. (Імовірно, якщо він ще не розпочався, deref
це означає, що він починає виконуватися, але це теж не гарантується.)Хоча ви можете зробити вираз у майбутньому таким же складним, як і код, що слідує за створенням обіцянки, сумнівно, що це бажано. Це означає, що ф’ючерси дійсно більше підходять для швидких фонових розрахунків, тоді як обіцянки дійсно більше підходять для великих, складних шляхів виконання. З точки зору доступних розрахунків, обіцянки здаються трохи більш гнучкими та орієнтованими на те, що творець обіцянок виконує роботу, і ще на одну нитку, яка збирає урожай. Ф'ючерси більше орієнтовані на автоматичний запуск потоку (без потворних та схильних до помилок накладних витрат) і продовження інших справ, поки вам - вихідному потоку - не знадобляться результати.
future
основна частина дзвінка може включати N sexprs.
Майбутнє і Обіцянка є механізмами передачі результату асинхронних обчислень від виробника до споживача.
У разі майбутнього обчислення визначаються в момент створення майбутнього і асинхронне виконання починається «якомога швидше». Він також "знає", як створити асинхронне обчислення.
У разі обчислення Promise час його початку та [можливий] асинхронний виклик відокремлюються від механізму доставки. Коли доступний результат обчислення , Виробник повинен зателефонувати явно, що також означає, що Виробник контролює, коли результат стане доступним. deliver
Для Promises Clojure допускає помилку в дизайні, використовуючи один і той же об'єкт (результат promise
виклику) як для виробництва ( deliver
), так і для споживання ( deref
) результату обчислення . Це дві дуже різні можливості, і їх слід розглядати як такі.
promise
буде зручним поєднання захисту з таким простим посилальним типом (перевірте його impl) . «Злі» споживачі трапляються рідко; ніщо не заважає вам побудувати власну абстракцію на додаток до обіцянок.
(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))))
Уже є відмінні відповіді, тому лише додавши резюме "як використовувати":
І те, і інше
Створення обіцянки або майбутнього негайно повертає посилання. Це посилання блокується на @ / deref, поки результат обчислення не буде наданий іншим потоком.
Майбутнє
Створюючи майбутнє, ви забезпечуєте синхронну роботу, яку потрібно виконати. Він виконується в потоці з виділеного необмеженого пулу.
Пообіцяй
Ви не наводите аргументів під час створення обіцянки. Посилання слід передати іншому потоку користувача, який буде deliver
результатом.
У Clojure, promise
, future
і delay
цю обіцянку, як об'єкти. Всі вони представляють обчислення, на які клієнти можуть чекати, використовуючи deref
(або @
). Клієнти повторно використовують результат, так що обчислення не запускаються кілька разів.
Вони відрізняються способом виконання обчислень:
future
розпочне обчислення в іншому робочому потоці. deref
буде блокувати, поки результат не буде готовий.
delay
буде виконувати обчислення ліниво, коли перший клієнт використовує deref
, або force
.
promise
пропонує найбільшу гнучкість, оскільки його результат доставляється будь-яким спеціальним способом за допомогою deliver
. Ви можете використовувати його , коли ні future
або delay
відповідати вашому випадку використання.
По-перше, 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
ви, яке ви зробили для себе.