当前位置: 首页 > 知识库问答 >
问题:

异步处理,使用Scala futures列表和onComplete进行异常处理

吕鸿轩
2023-03-14

我正在尝试进行大量的外部服务调用,每个调用都遵循异常处理和有条件的进一步处理。我认为使用内部的. on完成来扩展这个不错的(Scala中带有期货的异步IO)示例会很容易,但似乎我对范围和/或期货有些不理解。有人能给我指出正确的方向吗?

#!/bin/bash
scala -feature $0 $@
exit
!#

import scala.concurrent.{future, blocking, Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.util.{Success, Failure}
import scala.language.postfixOps

val keylist = List("key1", "key2")

val myFuts: List[Future[String]] = keylist.map {
  myid => future {
    // this line simulates an external call which returns a future (retrieval from S3)
    val myfut = future { Thread.sleep(1); "START " + myid}

    var mystr = "This should have been overwritten"
    myfut.onComplete {
      case Failure(ex) => {
        println (s"failed with error: $ex")
        mystr = "FAILED"
      }
      case Success(myval) => {
        mystr = s"SUCCESS $myid: $myval"
        println (mystr)
      }
    }
    mystr
  }
}

val futset: Future[List[String]] = Future.sequence(myFuts)
println (Await.result(futset, 10 seconds))

在我的电脑上(Scala 2.10.4 ),这打印出来:

SUCCESS key2: START key2
SUCCESS key1: START key1
List(This should have been overwritten, This should have been overwritten)

我要(顺序不重要):

SUCCESS key2: START key2
SUCCESS key1: START key1
List(SUCCESS key2: START key2, SUCCESS key1: START key1)

共有2个答案

巫经义
2023-03-14

完成后不会返回一个新的未来,它只允许您在未来完成时做一些事情。因此,未来的第一个块将在执行onComplete之前返回,因此您将返回字符串的原始值。

我们能做的就是用一个promise,去回报另一个未来,而这个未来是由第一个未来的结果来完成的。

  val keylist = List("key1", "key2")

  val myFuts: List[Future[String]] = keylist.map {
    myid => {
      // this line simulates an external call which returns a future (retrieval from S3)
      val myfut = Future {
        Thread.sleep(1); "START " + myid
      }
      var mystr = "This should have been overwritten"
      val p = Promise[String]()
      myfut.onComplete {
        case Failure(ex) =>
          println(s"failed with error: $ex")
          mystr = "FAILED"
          p failure ex
        case Success(myval) =>
          mystr = s"SUCCESS $myid: $myval"
          println(mystr)
          p success myval
      }
      p.future
    }
  }

  val futset: Future[List[String]] = Future.sequence(myFuts)
  println(Await.result(futset, 10 seconds))

超级方便的是mapAll方法,正如我在这里所问的那样:为成功和失败绘制未来地图

经佐
2023-03-14

我会避免使用 onComplete 并尝试使用它来对可变变量进行副作用逻辑。相反,我会映射未来,并将失败情况处理为返回不同的值。下面是一个稍微修改过的代码版本,使用 map on the Future(通过 a 进行理解),然后使用 recover 来处理失败的情况。希望这就是你一直在寻找的:

val keylist = List("key1", "key2")

val myFuts: List[Future[String]] = keylist.map {myid => 

  // this line simulates an external call which returns a future (retrieval from S3)
  val myfut = future { Thread.sleep(1); "START " + myid}
  val result = for (myval <- myfut) yield {
    val res = s"SUCCESS $myid: $myval"
    println(res)
    res
  }
  result.recover{
    case ex => 
      println (s"failed with error: $ex")
      "FAILED"          
  }

}

val futset: Future[List[String]] = Future.sequence(myFuts)
println (Await.result(futset, 10 seconds))
 类似资料:
  • 问题内容: 假设我有一个抛出某种Exception的方法。引发异常的代码位于访问外部服务的第三方库中。我有一些课程可以很好地处理外部服务,并且有很多异常处理程序可以处理潜在的问题。我遇到的问题是我可能有很多异常,但是如果有一个动作,并且可能有大量尝试/捕获块,我可能只需要执行几个动作之一。异常的类型甚至可能不相关,或者不同的方法可能会抛出相同类型的异常,但是根据抛出该异常的方法,需要采取不同的操作

  • 问题内容: 我目前正在使用node.js应用程序,并且遇到了通常的异步代码问题。 我正在Node的HTTP模块之上实现服务服务器。 该服务器支持(类似表达)路由。例如,我有如下代码: 服务器需要能够承受故障,当传递给任何函数的问题出现时,我不想使整个服务器崩溃。当我编写如下代码时,会发生问题: 我看不到如何在这里捕获错误。我不想因一个服务器端故障而使服务器崩溃,而是要服务500个。 我能够提出的唯

  • 我是一个有Spring和Spring靴的新手。在创建了一个简单的REST API来对用户执行CRUD操作之后,我还创建了自定义的异常处理程序来捕获应用程序中发生的任何异常。这是我写的代码 controller类 使用@ControllerAdvice注释的异常处理程序类 但是,当发生任何异常时,应用程序将被重定向到/error page,而不是由异常处理程序类处理。谁能给出正确的方法来做这件事。

  • 问题内容: 什么是处理这种情况的最佳方法。我处于受控环境中,所以我不想崩溃。 从setTimeout内抛出时,我们将始终获得: 如果抛出发生在setTimeout之前,那么bluebirds catch将捕获它: 结果是: 很棒-但是如何在节点或浏览器中处理这种性质的恶意异步回调。 问题答案: 承诺不是域,它们不会捕获异步回调中的异常。你就是做不到。 然而诺言来捕捉从内抛出的异常/ / 构造函数的

  • 问题内容: 什么是处理这种情况的最佳方法。我处于受控环境中,所以我不想崩溃。 从setTimeout内抛出时,我们将始终获得: 如果抛出发生在setTimeout之前,那么bluebirds catch将捕获它: 结果是: 很棒-但是如何在节点或浏览器中处理这种性质的恶意异步回调。 问题答案: 承诺不是域,它们不会捕获异步回调中的异常。你就是做不到。 然而诺言来捕捉从内抛出的异常/ / 构造函数的

  • 我想使用异步并等待处理承诺。我想在下面的示例中使用这个方法: 在执行时,它给了我一个错误 错误: UnhandledPromiseRejectionWarning:未处理得承诺拒绝.这个错误可能是由于抛出一个没有catch块的异步函数内部,或者是由于拒绝了一个未用.catch()处理的承诺。(拒绝ID:3)