И фьючерсы, и обещания блокируются до тех пор, пока не будут вычислены их значения, так в чем же между ними разница?
И фьючерсы, и обещания блокируются до тех пор, пока не будут вычислены их значения, так в чем же между ними разница?
Ответы:
Отвечая на языке 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
это означает, что он начинает выполняться, но это тоже не гарантируется.)Хотя в будущем вы могли бы сделать выражение таким же сложным, как код, следующий за созданием обещания, сомнительно, что это желательно. Это означает, что фьючерсы действительно больше подходят для быстрых, фоновых вычислений, в то время как обещания больше подходят для больших и сложных путей выполнения. Кроме того, с точки зрения доступных вычислений, обещания кажутся немного более гибкими и ориентированными на создателя обещаний, выполняющего работу, и на другой поток, собирающий урожай. Futures больше ориентированы на автоматический запуск потока (без уродливых и подверженных ошибкам накладных расходов) и продолжение других дел, пока вам - исходному потоку - не понадобятся результаты.
future
вызова может включать N sexprs.
И Future, и Promise - это механизмы для передачи результата асинхронных вычислений от производителя к потребителю (ям).
В случае будущего вычисления определяются в момент создания будущего и асинхронное исполнения начинается «как можно скорее». Он также «знает», как вызвать асинхронное вычисление.
В случае Promise вычисления , его время начала и [возможно] асинхронного вызова отделены от механизма доставки. Когда доступен результат вычисления, производитель должен вызывать deliver
явно, что также означает, что производитель контролирует, когда результат становится доступным.
Для промисов Clojure совершает ошибку в дизайне, используя один и тот же объект (результат promise
вызова) как для создания ( deliver
), так и для потребления ( deref
) результата вычисления . Это две очень разные возможности, и их следует рассматривать как таковые.
promise
было бы удобно привязать безопасность к такому простому ссылочному типу (проверьте его имплицит) . «Злые» потребители редки; ничто не мешает вам построить свою собственную абстракцию поверх обещаний.
(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
- это Future
. Я думаю, вы хотите знать разницу между a Promise
и a FutureTask
.
A Future
представляет значение, которое в настоящее время неизвестно, но будет известно в будущем.
A FutureTask
представляет результат вычислений, которые произойдут в будущем (возможно, в некотором пуле потоков). Когда вы пытаетесь получить доступ к результату, если вычисление еще не произошло, он блокируется. В противном случае результат возвращается немедленно. Никакая другая сторона не участвует в вычислении результата, поскольку вычисление указывается вами заранее.
A Promise
представляет результат, который обещатель будет доставлен обещающему в будущем. В этом случае вы являетесь обещателем, а обещающим является тот, кто дал вам Promise
объект. Подобно тому FutureTask
, как если вы пытаетесь получить доступ к результату до того, Promise
как было выполнено, он блокируется до тех пор, пока промайзер не выполнит Promise
. После Promise
выполнения вы всегда и сразу получаете одно и то же значение. В отличие от a FutureTask
, здесь участвует другая сторона, которая создала файл Promise
. Другая сторона несет ответственность за выполнение вычислений и выполнение Promise
.
В этом смысле, FutureTask
это Promise
вы сделали для себя.