In che modo differiscono i futuri e le promesse di Clojure?


86

Sia i futures che le promesse si bloccano fino a quando non hanno calcolato i loro valori, quindi qual è la differenza tra loro?


8
Non sono sicuro del motivo per cui il -1 sulla domanda, o sono domande di cui non conosci la risposta prima di chiederti cose brutte?
SOLO LA MIA OPINIONE corretta

Non ho -1 nessuna delle risposte ?? Come possiamo sapere chi ha messo -1 su una domanda o una risposta?
appshare.co

Tu ed io non possiamo, Zubair. Sono solo curioso di sapere chi ha messo un -1 alla tua domanda dato che è una domanda perfettamente ragionevole da porre ed è decisamente in tema per SO.
SOLO LA MIA OPINIONE corretta

Risposte:


54

Rispondendo in termini di Clojure, ecco alcuni esempi dallo screencast di Sean Devlin :

(def a-promise (promise))
(deliver a-promise :fred)

(def f (future (some-sexp)))
(deref f)

Si noti che nella promessa si fornisce esplicitamente un valore selezionato in un calcolo successivo ( :fredin questo caso). Il futuro, invece, si consuma nello stesso luogo in cui è stato creato. Il some-exprè presumibilmente lanciato dietro le quinte e calcolato in tandem (eventualmente), ma se rimane non valutata dal tempo si accede al blocchi di filettatura finché non è disponibile.


modificato per aggiungere

Per aiutare a distinguere ulteriormente tra una promessa e un futuro, nota quanto segue:

promettere

  1. Crei un file promise. Quell'oggetto promessa può ora essere passato a qualsiasi thread.
  2. Continui con i calcoli. Questi possono essere calcoli molto complicati che coinvolgono effetti collaterali, download di dati, input dell'utente, accesso al database, altre promesse, qualunque cosa tu voglia. Il codice assomiglierà molto al codice della linea principale in qualsiasi programma.
  3. Quando hai finito, puoi deliver i risultati di quell'oggetto promesso.
  4. Qualsiasi elemento che cerca di derefmantenere la tua promessa prima che tu abbia finito con il tuo calcolo si bloccherà finché non avrai finito. Una volta che hai finito e hai modificato deliverla promessa, la promessa non si bloccherà più.

futuro

  1. Tu crei il tuo futuro. Parte del tuo futuro è un'espressione per il calcolo.
  2. Il futuro può o non può essere eseguito contemporaneamente. Potrebbe essere assegnato un thread, possibilmente da un pool. Potrebbe solo aspettare e non fare nulla. Dal tuo punto di vista non puoi dirlo .
  3. Ad un certo punto tu (o un altro thread) sei derefil futuro. Se il calcolo è già stato completato, ne ottieni i risultati. Se non è già stato completato, blocchi finché non lo ha fatto. (Presumibilmente, se non è ancora iniziato, derefsignifica che inizia l'esecuzione, ma anche questo non è garantito.)

Anche se in futuro potresti rendere l'espressione complicata come il codice che segue la creazione di una promessa, è dubbio che sia desiderabile. Ciò significa che i futures sono davvero più adatti a calcoli rapidi e in background, mentre le promesse sono davvero più adatte a percorsi di esecuzione ampi e complicati. Inoltre, le promesse sembrano, in termini di calcoli disponibili, un po 'più flessibili e orientate verso il creatore della promessa che fa il lavoro e un altro filo che raccoglie il raccolto. I futuri sono più orientati verso l'avvio automatico di un thread (senza il sovraccarico brutto e soggetto a errori) e andare avanti con altre cose fino a quando tu - il thread di origine - hai bisogno dei risultati.


Ma puoi avere qualsiasi blocco di caluclation fino a quando una promessa OPPURE un futuro non è finito. ad esempio: (@a + @b) funzionerà allo stesso modo sia con un futuro che con una promessa
appshare.co

2
Una promessa consente una maggiore flessibilità, mi sembra. Creo una promessa. Passo quella promessa a un altro thread. Posso quindi eseguire molti calcoli complicati, tra cui l'attesa dell'I / O, il download di dati da Internet, l'attesa dell'input dell'utente, ecc. Quando tutto è finito, mantengo la promessa con il valore risultante. Un futuro copre un'espressione S. Potrebbe, immagino, essere un'espressione S molto, molto complicata, ma sarebbe un po '... rigida lì. Inoltre un futuro fa il suo lavoro automaticamente in un thread (o pool). Fare lo stesso in una promessa significherebbe ancora più lavoro.
SOLO LA MIA OPINIONE corretta

FWIW poiché una singola espressione s può essere una chiamata a un percorso di codice arbitrario, non si tratta necessariamente della quantità di codice che è possibile inserire nell'espressione. Quindi, invece di dire che una promessa è "più flessibile", direi che il suo scopo è semplicemente diverso. Altrimenti, perché avere entrambi?
Geoff

2
Solo per la cronaca, il corpo di una futurechiamata può includere N sexprs.
vemv

Questa spiegazione dovrebbe far parte di Clojure Doc
Piyush Katariya il

25

Sia Future che Promise sono meccanismi per comunicare il risultato del calcolo asincrono dal produttore al consumatore (i).

In caso di Future, il calcolo è definito al momento della creazione di Future e l'esecuzione asincrona inizia "ASAP". Inoltre "sa" come generare un calcolo asincrono.

In caso di Promise, il calcolo , la sua ora di inizio e [possibile] invocazione asincrona sono disaccoppiati dal meccanismo di consegna. Quando il risultato del calcolo è disponibile, Producer deve chiamare deliveresplicitamente, il che significa anche che Producer controlla quando risultato diventa disponibile.

For PromisesClojure commette un errore di progettazione utilizzando lo stesso oggetto (risultato della promisechiamata) sia per produrre ( deliver) che per consumare ( deref) il risultato del calcolo . Queste sono due capacità molto distinte e dovrebbero essere trattate come tali.


@oskarkv Supponi di aver creato una promessa e di averla data a 3 clienti. Niente impedisce a uno dei client di risolverlo con risultati falsi e di segnalarlo ad altri due client. Inoltre non sarai più in grado di risolvere questa promessa. Al contrario, se avessi una coppia promessa + risolutore, fatto promesse ai tuoi clienti e mantenuto risolutore per te stesso, questo scenario diventa impossibile. Per ulteriori informazioni, i termini di ricerca suggeriti sono "controllo dell'accesso basato sulla capacità" e "sicurezza basata sulla capacità".
Dimagog

1
Non sono sicuro che accoppiare la sicurezza a un tipo di riferimento così semplice (controlla il suo impl) come promisesarebbe conveniente. I consumatori "cattivi" sono rari; niente ti impedisce di costruire la tua astrazione in cima alle promesse.
vemv

8
Non si tratta di sicurezza, accade solo che la programmazione basata sulle capacità sia spesso descritta in relazione alla sicurezza. Qui è tutta una questione di correttezza del codice. Il termine spesso usato è "corretto per costruzione" e la domanda è "puoi costruire un programma errato"? Non apposta, ma per caso. Con un singolo oggetto Promise puoi, mentre con due oggetti separati non puoi.
Dimagog

Non c'è nulla che ti impedisca di restituire una promessa che non può essere mantenuta, se è quello che vuoi: (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))))
tapichu

Sottolineare la differenza nel modo in cui il meccanismo di calcolo è disaccoppiato ha reso questo post una spiegazione davvero concisa. Grazie!
synthomat

3

Ci sono già ottime risposte quindi aggiungendo solo il riepilogo "come usare":

Tutti e due

La creazione di promesse o future restituisce immediatamente un riferimento. Questo riferimento si blocca su @ / deref finché il risultato del calcolo non viene fornito da un altro thread.

Futuro

Quando crei il futuro, fornisci un lavoro sincrono da fare. Viene eseguito in un thread dal pool illimitato dedicato.

Promettere

Non dai argomenti quando crei una promessa. Il riferimento dovrebbe essere passato ad un altro thread "utente" che ne darà deliveril risultato.


1

In Clojure, promise, future, e delaysono promessa come oggetti. Rappresentano tutti un calcolo che i client possono attendere utilizzando deref(o @). I client riutilizzano il risultato, in modo che il calcolo non venga eseguito più volte.

Differiscono nel modo in cui viene eseguito il calcolo:

  • futureinizierà il calcolo in un diverso thread di lavoro. derefsi bloccherà fino a quando il risultato non sarà pronto.

  • delayeseguirà il calcolo pigramente, quando il primo client usa deref, o force.

  • promiseoffre la massima flessibilità, poiché il risultato viene fornito in qualsiasi modo personalizzato utilizzando deliver. Lo usi quando nessuno dei due futureo delaycorrisponde al tuo caso d'uso.


-4

In primo luogo, a Promiseè a Future. Penso che tu voglia conoscere la differenza tra a Promisee a FutureTask.

A Futurerappresenta un valore che non è attualmente noto ma lo sarà in futuro.

A FutureTaskrappresenta il risultato di un calcolo che avverrà in futuro (forse in qualche pool di thread). Quando si tenta di accedere al risultato, se il calcolo non è ancora avvenuto, si blocca. In caso contrario, il risultato viene restituito immediatamente. Non ci sono altre parti coinvolte nel calcolo del risultato poiché il calcolo è stato specificato in anticipo.

A Promiserappresenta un risultato che verrà consegnato dal promettente al promesso in futuro. In questo caso tu sei il promesso e il promettente è colui che ti ha dato l' Promiseoggetto. Simile a FutureTask, se si tenta di accedere al risultato prima che Promisesia stato soddisfatto, viene bloccato fino a quando il promettente non soddisfa il Promise. Una volta Promisesoddisfatto, ottieni sempre e immediatamente lo stesso valore. A differenza di a FutureTask, qui è coinvolta un'altra parte, che ha creato il file Promise. Che un'altra parte sia responsabile per il calcolo e l'adempimento del Promise.

In questo senso, a FutureTaskè un Promisefatto a te stesso.


Sei sicuro che una promessa sia un futuro? Non riesco a trovare che implementa l'interfaccia. github.com/richhickey/clojure/blob/…
Mikael Sundberg

scusa, ho premuto male per entrare. La mia domanda è cambiata
Mikael Sundberg

La mia risposta è in senso generale, non in quello specifico di Clojure.
Abhinav Sarkar

9
Rispondere a una domanda su Clojure con codice Java sembra un po 'bizzarro.
SOLO LA MIA OPINIONE corretta
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.