И фьючерсы, и обещания блокируются до тех пор, пока не будут вычислены их значения, так в чем же между ними разница?
И фьючерсы, и обещания блокируются до тех пор, пока не будут вычислены их значения, так в чем же между ними разница?
Ответы:
Отвечая на языке 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вы сделали для себя.