【问题标题】:How to fail promise in Scala如何在 Scala 中失败承诺
【发布时间】:2015-07-23 01:15:20
【问题描述】:

在 Scala 文档中,有一个示例如何选择通过使用 Promise 更快地成功的未来。

http://docs.scala-lang.org/overviews/core/futures.html#promises

def first[T](f: Future[T], g: Future[T]): Future[T] = {
  val p = promise[T]
  f onSuccess {
    case x => p.trySuccess(x)
  }
  g onSuccess {
    case x => p.trySuccess(x)
  }
  p.future
}

这个函数返回最先成功的未来,如果其中任何一个失败,它永远不会完成。

是否有可能以某种方式修改它,即使其他未来失败,如果成功则返回第二个,如果两者都成功,则像现在的代码一样选择更快的一个。

【问题讨论】:

    标签: scala promise future


    【解决方案1】:

    你可以添加这个:

    f onFailure {
      case e =>
        g onFailure {
          case _ =>
            p.failure(e)
        }
    }
    

    当两个期货都失败时,这将使承诺失败,与f 相同的异常。您可以对此进行详细说明,以创建一个异常,记录来自 fg 的 2 个异常(如有必要)。

    【讨论】:

    • 不要使用异常,而是使用Either monad。
    • @riccardo.cardin 在这里使用Either 是愚蠢的,因为未来已经通过成功和失败状态封装了Either。在这种情况下,使用 Either 只是重新发明轮子。
    【解决方案2】:

    我建议你在 Scala here987654321@

    中遵循 Alvin Alexander 的建议

    我相信这是处理期货的最佳方式

    package futures
    
    import scala.concurrent.{Future => ConcurrentTask}           // rename
    import scala.concurrent.ExecutionContext.Implicits.global
    import scala.util.{Failure, Success}
    import Utils.sleep
    
    object FutureAsConcurrentTask extends App {
    
      // run some long-running task (task has type Future[Int] in this example)
      val task = ConcurrentTask {
        Cloud.executeLongRunningTask
      }
    
      // whenever the task completes, execute this code
      task.onComplete {
        case Success(value) => println(s"Got the callback, value = $value")
        case Failure(e) => println(s"D'oh! The task failed: ${e.getMessage}")
      }
    
      // do your other work
      println("A ..."); sleep(100)
      println("B ..."); sleep(100)
      println("C ..."); sleep(100)
      println("D ..."); sleep(100)
      println("E ..."); sleep(100)
      println("F ..."); sleep(100)
    
    }
    

    【讨论】:

      【解决方案3】:

      这是一个基本模式,用于选择最快的未来或如果它们都太慢则超时:

      import scala.concurrent._
      import scala.concurrent.duration._
      import scala.concurrent.ExecutionContext.Implicits.global
      import scala.util.{ Success, Failure }
      import akka.actor._
      import akka.pattern.after
      
      object GetFastestFutureOrTimeout extends App {
        val e = new TimeoutException("TimeoutException")
        val system = ActorSystem("GetFastestFutureOrTimeout")
        val f1 = Future { Thread.sleep(200); "this is f1" }
        val f2 = Future { Thread.sleep(100); "this is f2" }
        val timeoutFuture = after(500.milliseconds, using = system.scheduler) { Future.failed(e) }
        val f = Future.firstCompletedOf(f1 :: f2 :: timeoutFuture :: Nil)
      
        f onComplete {
          case Success(msg) => println(msg)
          case Failure(err) => println("An error occured: " + err.getMessage)
        }
      }
      

      这会打印“这是 f2”。如果将 timeoutFuture 的超时时间更改为 50,则会打印“发生错误:TimeoutException”。

      在底层 firstCompletedOf 使用 Promise 返回第一个完成的 Future 的值,请参阅 https://github.com/scala/scala/blob/v2.11.6/src/library/scala/concurrent/Future.scala#L503

      【讨论】:

        【解决方案4】:

        这是一个基本实现,用于获取最快的成功响应或如果都失败则失败:

        def getFirstSuccessfulResultOrFail[T](requests: List[Future[T]]): Future[T] = {
          val p              = Promise[T]()
          val countDownLatch = AtomicInt(0)
        
          requests.foreach { f =>
            f.onComplete {
              case Failure(e) => if (countDownLatch.addAndGet(1) == requests.size) p.tryFailure(e)
              case Success(s) => p.trySuccess(s)
            }
          }
        
          p.future
        }
        

        【讨论】:

          猜你喜欢
          • 2012-06-28
          • 1970-01-01
          • 2017-11-01
          • 1970-01-01
          • 2014-02-23
          • 2019-02-15
          • 1970-01-01
          • 2019-09-27
          • 1970-01-01
          相关资源
          最近更新 更多