Чем отличаются фьючерсы и обещания Clojure?

И фьючерсы, и обещания блокируются, пока они не вычислили свои значения, так в чем же разница между ними?

6 ответов

Решение

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

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

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

В случае Future вычисление определяется во время создания Future, и асинхронное выполнение начинается как можно скорее. Он также "знает", как создавать асинхронные вычисления.

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

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

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

И то и другое

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

Будущее

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

обещание

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

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

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

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

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

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

Я думаю, что глава 9 Clojure for the Brave лучше всего объясняет разницу между , , а также .

Идея, объединяющая эти три концепции, заключается в следующем: жизненный цикл задачи. Задачу можно представить как прохождение трех этапов: задача определяется, задача выполняется, результат задачи используется.

Некоторые языки программирования (например, JavaScript) имеют конструкции с одинаковыми названиями (например, JS), которые объединяют несколько (или все) этапов жизненного цикла задачи. В JS, например, невозможно построить объект, не предоставив ему либо функцию (задачу), которая будет вычислять его значение, либо сразу с постоянным значением.

Clojure, однако, избегает такой связи и по этой причине имеет три отдельные конструкции, каждая из которых соответствует одному этапу жизненного цикла задачи.

  1. определение задачи
  2. : выполнение задачи
  3. : результат задачи

Каждая конструкция связана со своим собственным этапом жизненного цикла задачи и ни с чем другим, таким образом распутывая конструкции более высокого порядка, такие как JS, и разделяя их на соответствующие части.

Теперь мы видим, что в JavaScript a - это комбинация всех трех конструкций Clojure, перечисленных выше. Пример:

      const promise = new Promise((resolve) => resolve(6))

Давайте разберемся:

  1. определение задачи: это задача.
  2. выполнение задачи: здесь подразумевается контекст выполнения, а именно то, что эта задача будет выполняться в будущем цикле цикла событий. Вы не имеете права голоса в этом; вы не можете, например, требовать, чтобы эта задача решалась синхронно, потому что асинхронность встроена сама в себя. Обратите внимание, как при построении вы уже запланировали выполнение своей задачи (в какое-то неопределенное время). Вы не можете сказать «позвольте мне передать это другому компоненту моей системы и позволить ему решать, когда он хочет запустить эту задачу».
  3. результат задачи: результат задачи запекается в объект и может быть получен ing или ing. Невозможно создать «пустой» обещанный результат, который позже будет заполнен какой-то еще неизвестной частью вашей системы; вы должны как определить задачу, так и одновременно запланировать ее выполнение.

PS: Разделение, которое накладывает Clojure, позволяет этим конструкциям брать на себя роли, для которых они не подходили бы, если бы были тесно связаны. Например, Clojure , будучи отделенным от определения и выполнения задачи, теперь может использоваться как единица передачи между потоками.

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

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

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

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

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

Другие вопросы по тегам