Futures / Success race

后端 未结 3 1609
遥遥无期
遥遥无期 2020-12-04 01:45

I\'m learning futures, and I\'m trying to create a method that, take two futures as parameter (f and g) and return the first future that was succes

相关标签:
3条回答
  • 2020-12-04 02:20

    You want to use the tryCompleteWith method. It can be called multiple times and only the first completing future wins.

    def successRace(f: Future[T], g: Future[T]): Future[T] = {
      val p = Promise[T]()
      p.tryCompleteWith(f)
      p.tryCompleteWith(g)
      p.future
    }
    
    0 讨论(0)
  • 2020-12-04 02:40

    I completely agree with the previous answer, still i hope my example will clarify it a bit further, so:

    def successRace[T](f: Future[T], g: Future[T]): Future[T] = {
      val promise = Promise[T]()
    
      f onComplete(promise.tryComplete(_))
      g onComplete(promise.tryComplete(_))
    
      promise.future
    }
    

    so the first completed Future will set the value wrapped in Try (so, Success or Failure).

    0 讨论(0)
  • 2020-12-04 02:47

    The use case is the first successful completion:

    scala> :pa
    // Entering paste mode (ctrl-D to finish)
    
    def firstSuccessOf[T](fs: Future[T]*)(implicit x: ExecutionContext): Future[T] = {
      val p = Promise[T]()
      val count = new java.util.concurrent.atomic.AtomicInteger(fs.size)
      def bad() = if (count.decrementAndGet == 0) { p tryComplete new Failure(new RuntimeException("All bad")) }
      val completeFirst: Try[T] => Unit = p tryComplete _
      fs foreach { _ onComplete { case v @ Success(_) => completeFirst(v) case _ => bad() }}
      p.future
    }
    
    // Exiting paste mode, now interpreting.
    
    firstSuccessOf: [T](fs: scala.concurrent.Future[T]*)(implicit x: scala.concurrent.ExecutionContext)scala.concurrent.Future[T]
    

    so

    scala> def f = Future { Thread sleep 5000L ; println("Failing") ; throw new NullPointerException }
    f: scala.concurrent.Future[Nothing]
    
    scala> def g = Future { Thread sleep 10000L ; println("OK") ; 7 }
    g: scala.concurrent.Future[Int]
    
    scala> firstSuccessOf(f,g)
    res3: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@5ed53f6b
    
    scala> res0Failing
              3.value
    res4: Option[scala.util.Try[Int]] = None
    
    scala> res3.valueOK
    
    res5: Option[scala.util.Try[Int]] = Some(Success(7))
    

    or

    scala> def h = Future { Thread sleep 7000L ; println("Failing too") ; throw new NullPointerException }
    h: scala.concurrent.Future[Nothing]
    
    
    scala> firstSuccessOf(f,h)
    res10: scala.concurrent.Future[Nothing] = scala.concurrent.impl.Promise$DefaultPromise@318d30be
    
    scala> 
    
    scala> res10.Failing
    value
    res11: Option[scala.util.Try[Nothing]] = None
    
    scala> Failing too
    
    
    scala> res10.value
    res12: Option[scala.util.Try[Nothing]] = Some(Failure(java.lang.RuntimeException: All bad))
    

    @ ysusuk 's answer is what Future.firstCompletedOf does under the hood.

    0 讨论(0)
提交回复
热议问题