Чем отличаются фьючерсы и обещания 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это означает, что он начинает выполняться, но это тоже не гарантируется.)

Хотя в будущем вы могли бы сделать выражение таким же сложным, как код, следующий за созданием обещания, сомнительно, что это желательно. Это означает, что фьючерсы действительно больше подходят для быстрых, фоновых вычислений, в то время как обещания больше подходят для больших и сложных путей выполнения. Кроме того, с точки зрения доступных вычислений, обещания кажутся немного более гибкими и ориентированными на создателя обещаний, выполняющего работу, и на другой поток, собирающий урожай. Futures больше ориентированы на автоматический запуск потока (без уродливых и подверженных ошибкам накладных расходов) и продолжение других дел, пока вам - исходному потоку - не понадобятся результаты.


Но вы можете иметь любой блок вычисления, пока не будет выполнено обещание ИЛИ будущее. то есть: (@a + @b) будет работать одинаково как с будущим, так и с обещанием
appshare.co

2
Обещание дает больше гибкости, как мне кажется. Я создаю обещание. Я передаю это обещание другому потоку. Затем я могу выполнить множество сложных вычислений, включая ожидание ввода-вывода, загрузку данных из Интернета, ожидание ввода данных пользователем и т. Д. Когда все будет сделано, я передаю обещание с полученным значением. Будущее покрывает одно S-выражение. Я думаю, это могло быть очень, очень сложное S-выражение, но оно было бы немного ... жестким. Вдобавок future выполняет свою работу автоматически в потоке (или пуле). То же самое в обещании означало бы еще больше работы.
ТОЛЬКО МОЕ ПРАВИЛЬНОЕ МНЕНИЕ

FWIW, поскольку одно s-выражение может быть вызовом произвольного пути кода, это не обязательно о том, сколько кода вы можете втиснуть в выражение. Поэтому вместо того, чтобы говорить, что обещание «более гибкое», я бы сказал, что его цель просто другая. Иначе зачем и то, и другое?
Джефф,

2
Для записи: тело futureвызова может включать N sexprs.
vemv

Это объяснение должно быть частью Clojure Doc
Пиюш Катария

25

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

В случае будущего вычисления определяются в момент создания будущего и асинхронное исполнения начинается «как можно скорее». Он также «знает», как вызвать асинхронное вычисление.

В случае Promise вычисления , его время начала и [возможно] асинхронного вызова отделены от механизма доставки. Когда доступен результат вычисления, производитель должен вызывать deliverявно, что также означает, что производитель контролирует, когда результат становится доступным.

Для промисов Clojure совершает ошибку в дизайне, используя один и тот же объект (результат promiseвызова) как для создания ( deliver), так и для потребления ( deref) результата вычисления . Это две очень разные возможности, и их следует рассматривать как таковые.


@oskarkv Предположим, вы создали обещание и дали его трем клиентам. Ничто не мешает одному из клиентов разрешить проблему с ложным результатом и сообщить об этом двум другим клиентам. К тому же вы больше не сможете выполнить это обещание. Напротив, если у вас была пара обещаний + преобразователя, вы дали обещание своим клиентам и оставили преобразователь для себя, этот сценарий становится невозможным. Для получения дополнительной информации предлагаются следующие термины для поиска: «управление доступом на основе возможностей» и «безопасность на основе возможностей».
Dimagog

1
Я не уверен, promiseбыло бы удобно привязать безопасность к такому простому ссылочному типу (проверьте его имплицит) . «Злые» потребители редки; ничто не мешает вам построить свою собственную абстракцию поверх обещаний.
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))))
тапичу

Указание на разницу в том, как механизм вычислений разделен, сделало этот пост действительно кратким объяснением. Благодарность!
Synthomat 03

3

Уже есть отличные ответы, поэтому добавляем только краткое изложение «как использовать»:

И то и другое

Создание обещания или будущего немедленно возвращает ссылку. Эта ссылка блокируется на @ / deref до тех пор, пока результат вычисления не будет предоставлен другим потоком.

Будущее

Создавая будущее, вы обеспечиваете синхронную работу. Он выполняется в потоке из выделенного неограниченного пула.

Обещание

Вы не приводите аргументов при создании обещания. Ссылка должна быть передана другому «пользовательскому» потоку, который выдаст deliverрезультат.


1

В Clojure, promise, futureи delayэто обещание, как объекты. Все они представляют собой вычисления, которые клиенты могут ожидать, используя deref(или @). Клиенты повторно используют результат, поэтому вычисление не запускается несколько раз.

Они различаются способом выполнения вычислений:

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

  • delayбудет выполнять вычисления лениво, когда первый клиент использует deref, или force.

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


-4

Во-первых, a Promise- это Future. Я думаю, вы хотите знать разницу между a Promiseи a FutureTask.

A Futureпредставляет значение, которое в настоящее время неизвестно, но будет известно в будущем.

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

A Promiseпредставляет результат, который обещатель будет доставлен обещающему в будущем. В этом случае вы являетесь обещателем, а обещающим является тот, кто дал вам Promiseобъект. Подобно тому FutureTask, как если вы пытаетесь получить доступ к результату до того, Promiseкак было выполнено, он блокируется до тех пор, пока промайзер не выполнит Promise. После Promiseвыполнения вы всегда и сразу получаете одно и то же значение. В отличие от a FutureTask, здесь участвует другая сторона, которая создала файл Promise. Другая сторона несет ответственность за выполнение вычислений и выполнение Promise.

В этом смысле, FutureTaskэто Promiseвы сделали для себя.


Вы уверены, что будущее - за обещанием? Я не могу найти, что он реализует интерфейс. github.com/richhickey/clojure/blob/…
Микаэль Сундберг,

извините, я неправильно набрал ввод. Мой вопрос изменен
Микаэль Сундберг

Я отвечу в общем смысле, а не конкретно в Clojure.
Абхинав Саркар

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