Je lis SIP-14 et le concept de Future
est parfaitement logique et facile à comprendre. Mais avez deux questions sur Promise
:
Le dit SIP
Depending on the implementation, it may be the case that p.future == p
. Comment se peut-il? SontFuture
etPromise
non deux types différents?Quand devrions-nous utiliser un
Promise
? L'exemple deproducer and consumer
code:import scala.concurrent.{ future, promise } val p = promise[T] val f = p.future val producer = future { val r = produceSomething() p success r continueDoingSomethingUnrelated() } val consumer = future { startDoingSomething() f onSuccess { case r => doSomethingWithResult() } }
est facile à lire mais avons-nous vraiment besoin d'écrire comme ça? J'ai essayé de l'implémenter uniquement avec Future et sans Promise comme ceci:
val f = future {
produceSomething()
}
val producer = future {
continueDoingSomethingUnrelated()
}
startDoingSomething()
val consumer = future {
f onSuccess {
case r => doSomethingWithResult()
}
}
Quelle est la différence entre cet exemple et l'exemple donné et qu'est-ce qui rend une promesse nécessaire?
scala
concurrency
Xiefei
la source
la source
Future
et ilPromise
existe deux types distincts, mais comme vous pouvez le voir sur github.com/scala/scala/blob/master/src/library/scala/concurrent/... cettePromise
implémentation particulière s'étendFuture
également.Réponses:
La promesse et l'avenir sont des concepts complémentaires. L'avenir est une valeur qui sera récupérée, enfin, dans le futur et vous pouvez en faire des choses lorsque cet événement se produit. C'est donc le point final de lecture ou de sortie d'un calcul - c'est quelque chose à partir duquel vous récupérez une valeur.
Une promesse est, par analogie, le côté écriture du calcul. Vous créez une promesse qui est l'endroit où vous placerez le résultat du calcul et à partir de cette promesse, vous obtenez un avenir qui sera utilisé pour lire le résultat qui a été mis dans la promesse. Lorsque vous accomplirez une promesse, que ce soit par échec ou par succès, vous déclencherez tout le comportement qui était attaché au futur associé.
Concernant votre première question, comment se fait-il que pour une promesse p que nous ayons
p.future == p
. Vous pouvez imaginer cela comme un tampon à un seul élément - un conteneur initialement vide et vous pouvez ensuite stocker une valeur qui deviendra son contenu pour toujours. Maintenant, selon votre point de vue, c'est à la fois une promesse et un avenir. C'est prometteur pour quelqu'un qui a l'intention d'écrire la valeur dans le tampon. C'est un avenir pour quelqu'un qui attend que cette valeur soit mise dans le tampon.Plus précisément, pour l'API simultanée Scala, si vous examinez le trait Promise ici, vous pouvez voir comment les méthodes de l'objet compagnon Promise sont implémentées:
Maintenant, ces implémentations de promesses, DefaultPromise et KeptPromise peuvent être trouvées ici . Ils étendent tous les deux un petit trait de base qui porte le même nom, mais il est situé dans un package différent:
Vous pouvez donc voir ce qu'ils veulent dire
p.future == p
.DefaultPromise
est le tamponKeptPromise
auquel je faisais référence ci-dessus, tandis que c'est un tampon avec la valeur mise depuis sa création même.En ce qui concerne votre exemple, le futur bloc que vous y utiliserez crée en fait une promesse dans les coulisses. Le regard Let la définition de
future
dans ici :En suivant la chaîne de méthodes, vous vous retrouvez dans le futur impl .
Ainsi, comme vous pouvez le voir, le résultat que vous obtenez de votre bloc de producteurs est versé dans une promesse.
MODIFICATION PLUS TARD :
En ce qui concerne l'utilisation dans le monde réel: la plupart du temps, vous ne traitez pas directement les promesses. Si vous utilisez une bibliothèque qui effectue un calcul asynchrone, vous ne travaillerez qu'avec les futurs retournés par les méthodes de la bibliothèque. Les promesses sont, dans ce cas, créées par la bibliothèque - vous travaillez simplement avec la fin de lecture de ce que font ces méthodes.
Mais si vous devez implémenter votre propre API asynchrone, vous devrez commencer à travailler avec elles. Supposons que vous ayez besoin d'implémenter un client HTTP asynchrone au-dessus de, disons, Netty. Ensuite, votre code ressemblera un peu à ceci
la source
Promise
s doit être dans le code d'implémentation.Future
est une bonne chose en lecture seule que vous pouvez exposer au code client. De plus, laFuture.future{...}
syntaxe peut parfois être lourde.def makeHTTPCall(request: Request): Future[Response] = { Future { registerOnCompleteCallback(buffer => { val response = makeResponse(buffer) response }) } }
registerOnCompleteCallback()
terminé. De plus, il ne revient pasFuture[Response]
. Il revient à laFuture[registerOnCompleteCallback() return type]
place.