【问题标题】:Another scala Futures composition puzzler另一个 scala Futures 组合谜题
【发布时间】:2016-09-12 15:36:48
【问题描述】:

我正在将代码从同步样式迁移到异步样式。问题相当简单:调用一系列函数,并在第一个函数处停止以返回非错误结果(返回该值,否则返回最后一个计算值)。我开始了:

def find(fs: Seq[Function0[Int]], result: Int = -1): Int = {
  if (fs.isEmpty) result
  else {
    val res = fs.head()
    if (res != 0) res
    else find(fs.tail, res)
  }
}

但是,如果函数变得异步,(即返回 Future[Int])我无法获得正确的调用。例如,

def ffind(ffs: Seq[Function0[Future[Int]]], result: Future[Int] = Future { -1 }): Future[Int] = {
  if (ffs.isEmpty) result
  else ffind(ffs.tail, ffs.head())
}

效果很好,但它会评估所有函数,而不考虑返回值。但类似:

def findBad(ffs: Seq[Function0[Future[Int]]], result: Future[Int] = Future { -1 }): Future[Int] = {
  if (ffs.isEmpty) result
  else {
      ffs.head() map { res =>
        if (res != 0) res
        else findBad(ffs.tail, Future(res))
      }
   }
}

不进行类型检查。有什么建议么?我们可以假设函数的每次调用都是昂贵的,因此不应该调用两次,也不应该在序列中的第一个“成功”调用之后调用。 TIA

【问题讨论】:

  • 嗨,这个问题解决了吗?
  • 是的,很抱歉我没有更新问题,只是支持答案。非常感谢!
  • 我只是在清理,因为我有强迫症所以我想知道我的回答是否解决了你的问题,在这种情况下你应该将其标记为已接受,或者它是不充分的,其中万一我会删除它。

标签: scala concurrent.futures


【解决方案1】:

这就是它不进行类型检查的原因:findBad 返回 Future[Int],但将 res 映射到对 findBad 的调用会导致 Future[Future[Int]]。您需要将map 更改为flatMap。请注意,现在您还需要将第一个条件(如果 res != 0)中的res 也包装成Future,以便两个分支都返回Future。代码如下:

ffs.head() flatMap { res =>
  if (res != 0) Future.succesful(res)
  else findBad(ffs.tail, Future(res))
}

顺便说一句,如果您想全部运行它们并返回先完成的那个,而忽略所有其余部分,那么这是一个有点不同的问题(请参阅here),但是您说每个函数调用都很昂贵,所以我怀疑这就是您正在尝试做。

【讨论】:

  • 永远不要将Future.apply 用于常量,这就是Future.successful 的设计目的。 Future(res) 将创建额外的不必要的工作,因为它被安排和执行,就好像结果未知一样。签名中甚至还需要implicit ex: ExecutionContext
  • 我在发布时就想到了这一点,但在这种情况下,我认为在实践中差异很小,所以我没有打扰编辑。但是好的,点了,会修改的。
猜你喜欢
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-05
  • 1970-01-01
  • 2013-04-24
  • 2017-01-19
  • 2012-11-10
相关资源
最近更新 更多