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

未来递归模式/任意长度的未来链

安坚诚
2023-03-14

我很好奇递归构建Akka期货链的最佳方式,它将按顺序运行,如果未来的< code>doWork调用失败,未来将重试3次,如果重试次数用完,链将失败。假设所有< code>doWork调用都通过,则返回的futChain应该只完成。

object Main extends App {
  val futChain = recurse(2)

  def recurse(param: Int, retries: Int = 3): Future[String] {
    Future {
      doWorkThatMayFailReturningString(param...)
    } recoverWith {
      case e => 
        if (retries > 0) recurse(param, retries -1)
        else  Future.failed(e)
    } flatMap {
      strRes => recurse(nextParam) //how should the res from the previous fut be passed?
    }
  }

  futChain onComplete {
    case res => println(res) //should print all the strings
  }
}
    < li >如何将结果作为集合获取?即,在本例中,从< code>doWork函数返回的每个< code>String(我需要以某种方式修改< code>recurse函数,以返回一个< code > future[List[String]] < li >我应该使用< code>recover还是< code>recoverWith? < li >可以调用< code>flatMap来链接这些调用吗 < li >我应该考虑尾部递归吗

共有1个答案

冯庆
2023-03-14

您可以像这样实现可重试的Future

def retry[T](f: => Future[T])(n: Int)(implicit e: ExecutionContext): Future[T] = {
    n match {
        case i if (i > 1) => f.recoverWith{ case t: Throwable => retry(f)(n - 1)}
        case _ => f
    }       
}

这没有针对尾部html" target="_blank">递归进行优化,但是如果您只打算重试几次,则不会得到堆栈溢出(我想如果它在前几个失败,无论如何它都会继续失败)。

然后我会单独做链接。如果您有有限数量的函数要链接在一起,每个函数都依赖于前面的函数(出于某种原因,您希望聚合结果),您可以使用< code > for comprehensions(< code > flat map 的语法糖):

for {
    firstResult <- retry(Future(doWork(param)))(3)
    secondResult <- retry(Future(doWork(firstResult)))(3)
    thirdResult <- retry(Future(doWork(secondResult)))(3)
} yield List(firstResult, secondResult, thirdResult)

对于任意长的链,您可以使用 Future.sequence(Akka 库中的 Futures)并行执行它们:

def doWork(param: String): String = ...

val parameters: List[String] = List(...)

val results: Future[List[String]] = Future.sequence(parameters.map(doWork(_)))

这将解开本来是< code > List[Future[String]]到< code > Future[List[String]]的关系。

以下是按顺序执行类似操作的一种方法:

def sequential[A, B](seq: List[A])(f: A => Future[B])(implicit e: ExecutionContext): Future[List[B]] = {
    seq.foldLeft(Future.successful(List[B]())) { case (left, next) =>
        left.flatMap(list => f(next).map(_ :: list))
    }
}

def doWork(param: String): String = ...

val results: Future[List[String]] = sequential(parameters)(param => Future(doWork(param))) 

这些功能的实现对您的用例非常敏感。如果链中的任何期货失败,上述两个函数将返回失败的期货。有时候你会想要这个,有时候不会。如果您想只收集成功的期货,并放弃失败的期货而不放弃整个结果,您可以添加一个额外的步骤来恢复失败。

此外,recoverrecoverWith 之间的区别在于它接受的 PartialFunction 的类型。recover 将失败的 future 替换为默认值,而 recoverWith 使用另一个 Future 执行此操作。在我重试的情况下,recoverWith 更合适,因为我正在尝试用自身来恢复失败的未来

 类似资料:
  • 好吧,我想问题已经在标题中完成了。没什么大不了的,但我只是想知道。我有一个返回正确值或错误代码枚举项的方法。例如这样的东西: 其中返回一个Future,而只是修改数据。 现在我已经直观地编写了< code>Future[_],因为返回值是灵活的。但是在查看其他库时,我看到了< code>Future[Any]的用法。当你在函数的返回中使用匹配用例来检查它是什么数据时,这似乎也是合乎逻辑的。 例如,

  • 任务是实现递归方法,返回 Future 并且由于这一部分("在其他递归(结果::: res,尝试1)")代码失败与错误,因为它期望未来[Seq[结果]],但实际上返回未来[对象]。 据我所知,问题在于yield块内的表达式必须返回Seq[Result],以便将来由Monad进行后续包装。但是“递归(结果::res,尝试1)”将返回未来。因此,不是预期的Seq[Result]收益率,而是包含未来的[

  • 我在写一个小服务器。一篇博文特别推荐了这种提问模式。课程具有以下特点: 我正在检索这个数据库行,如果它不存在或发生了一些错误,我想从Spray发送一个响应来告诉客户端。 然而,使用这种模式,我不知道在哪里注入开关。 我试着把代码改成这样: Spray使用发送HTTP响应可以接受两个对象,也可以接受一个字符串/可序列化对象。我想使用双对象模式(它允许我手动编码它的标题),理想的情况应该是 有没有办法

  • left join 和 inner join的区别 线程池的调用顺序 Spring循环依赖和三级缓存 AOP机制 索引 最左前缀原则的失效 ABCD 有>号 范围查询后会失效 MVCC的实现 可不可以实习

  • JavaScript未来的模块化会是什么样子?这很难讲。如前所说,ES6已经开始起草这一块的标准,而AMD,CommonJS已经流行起来。通常,标准的制定,都是在有了实现的前提之下。不管怎样,我们先来展望一二吧。

  • 问题内容: 信封:Akka 2.1,scala版本2.10.M6,JDK 1.7,u5 现在是我的问题:我有: 现在在第一行中,我有一个Future对象的Future,有什么方法可以在不阻塞当前线程的情况下将其转换为Future? Akka有什么方法吗?据我检查,我还没有发现…第一次发帖....不好意思的格式和组织…:〜P 问题答案: 简短答案(英语):flatMap dat sh!t 较短的答案