92 votes

Quels sont les cas d'utilisation de scala.de façon concomitante.Promesse?

Je suis de lecture SIP-14 et le concept de l' Future tout à fait logique et facile à comprendre. Mais deux questions à propos de Promise:

  1. Le SIP, dit - Depending on the implementation, it may be the case that p.future == p. Comment cela peut-il être? Sont - Future et Promise pas de deux types différents?

  2. Quand doit-on utiliser un Promise? L'exemple producer 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 la mettre en œuvre qu'avec l'Avenir et sans Promesse 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 cela et l'exemple donné et de ce fait une Promesse nécessaire?

116voto

Marius Danila Points 5075

La Promesse et l'Avenir sont des concepts complémentaires. L'Avenir est une valeur qui sera récupéré, bien, à un moment donné dans l'avenir et vous pouvez faire des trucs avec elle lorsque cet événement se produit. Il est, par conséquent, de le lire ou de point de terminaison d'un calcul - c'est quelque chose que vous récupérer une valeur à partir.

Une Promesse est, par analogie, l'écriture côté du calcul. Vous créez une promesse qui est l'endroit où vous allez mettre le résultat du calcul et de la promesse que vous obtenez un avenir qui sera utilisé pour lire le résultat qui a été mis dans la promesse. Lorsque vous allez remplir une Promesse, soit par l'échec ou le succès, vous réalisez tous les comportements qui était attachée au Futur associé.

Concernant votre première question, comment peut-il être que pour une promesse p nous avons p.future == p. Vous pouvez imaginer cela comme un simple élément de la mémoire tampon d'un conteneur qui est initialement vide et vous pouvez ensuite stocker une valeur qui deviendra son contenu à tout jamais. Maintenant, selon votre point de vue c'est à la fois une Promesse et un Avenir. C'est la promesse pour quelqu'un qui a l'intention d'écrire la valeur dans la mémoire tampon. C'est un avenir pour quelqu'un qui attend que la valeur à mettre dans la mémoire tampon.

Plus précisément, pour la Scala simultanées de l'API, si vous jetez un oeil à la Promesse de trait dans ici vous pouvez voir comment les méthodes de la Promesse compagnon objet sont mis en œuvre :

object Promise {

  /** Creates a promise object which can be completed with a value.
   *  
   *  @tparam T       the type of the value in the promise
   *  @return         the newly created `Promise` object
   */
  def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]()

  /** Creates an already completed Promise with the specified exception.
   *  
   *  @tparam T       the type of the value in the promise
   *  @return         the newly created `Promise` object
   */
  def failed[T](exception: Throwable): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception))

  /** Creates an already completed Promise with the specified result.
   *  
   *  @tparam T       the type of the value in the promise
   *  @return         the newly created `Promise` object
   */
  def successful[T](result: T): Promise[T] = new impl.Promise.KeptPromise[T](Success(result))

}

Maintenant, ceux de la mise en œuvre des promesses, DefaultPromise et KeptPromise peut être trouvé ici. Ils ont à la fois d'étendre une base petit trait qui arrive à avoir le même nom, mais il est situé dans un package différent:

private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
  def future: this.type = this
}

Donc vous pouvez voir ce qu'ils entendent par p.future == p.

DefaultPromise est le tampon je faisais allusion ci-dessus, tandis que d' KeptPromise est un tampon avec la valeur mis en depuis sa création.

Quant à votre exemple, l'avenir de bloc que vous utilisez, il crée en fait une promesse derrière les coulisses. Regardons la définition de l' future en ici :

def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)

En suivant la chaîne de méthodes vous vous retrouvez dans l' impl.Avenir:

private[concurrent] object Future {
  class PromiseCompletingRunnable[T](body: => T) extends Runnable {
    val promise = new Promise.DefaultPromise[T]()

    override def run() = {
      promise complete {
        try Success(body) catch { case NonFatal(e) => Failure(e) }
      }
    }
  }

  def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
    val runnable = new PromiseCompletingRunnable(body)
    executor.execute(runnable)
    runnable.promise.future
  }
}

Donc, comme vous pouvez le voir, le résultat que vous obtenez à partir de votre producteur bloc obtient versé dans une promesse.

ÉDITER PLUS TARD:

Quant à l'utilisation dans le monde réel: la Plupart du temps vous n'aurez pas à traiter avec des promesses directement. Si vous allez utiliser une bibliothèque qui effectue le calcul asynchrone ensuite, vous aurez juste à travailler avec les contrats à terme renvoyé par la bibliothèque de méthodes. Les promesses sont, dans ce cas, créé par la bibliothèque, vous êtes juste à travailler avec la lecture de la fin de ce que ces méthodes ne.

Mais si vous avez besoin de mettre en place votre propre asynchrone API, vous aurez à commencer à travailler avec eux. Supposons que vous avez besoin pour mettre en œuvre un async HTTP client sur le dessus, disons, de Netty. Puis votre code va ressembler à quelque chose comme ceci

    def makeHTTPCall(request: Request): Future[Response] = {
        val p = Promise[Response]
        registerOnCompleteCallback(buffer => {
            val response = makeResponse(buffer)
            p success response
        })
        p.future
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X